Подтвердить что ты не робот

Обнаруживать изменения в представлении прокрутки UIWebView contentSize

Я пытаюсь установить UIView в нижней части содержимого UIScrollView, сделайте так, чтобы я установил позицию представления в скобку scrollview. Но мой scrollview является подвидным интерфейсом UIWebView, поэтому при загрузке изображений изменяется размер содержимого и мое представление, которое должно быть в нижней части прокрутки, заканчивается посередине...

Итак, я ищу способ уведомления при изменении содержимого прокрутки. Я попытался подклассифицировать его и изменить setter для contensize, чтобы отправить NSNotification:

@implementation UIScrollView (Height)

-(void)setContentSize:(CGSize)contentSize
{
    _contentSize=contentSize;
    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:@"scrollViewContentSizeChanged" object:nil]];
}

@end

Но при компиляции я получаю сообщение об ошибке:

"_ OBJC_IVAR _ $_ UIScrollView._contentSize", на который ссылаются:       - [UIScrollView (Heigth) setContentSize:] в MyClass.o ld: символ не найден для архитектуры armv7

Любая идея, как сеттер должен быть подклассом?

Спасибо!

4b9b3361

Ответ 1

Возможно, вы можете использовать наблюдение за ключом (KVO) для обнаружения изменений в размере содержимого. Я не пробовал, но код должен выглядеть так:

static int kObservingContentSizeChangesContext;

- (void)startObservingContentSizeChangesInWebView:(UIWebView *)webView {
    [webView.scrollView addObserver:self forKeyPath:@"contentSize" options:0 context:&kObservingContentSizeChangesContext];
}

- (void)stopObservingContentSizeChangesInWebView:(UIWebView *)webView {
    [webView.scrollView removeObserver:self forKeyPath:@"contentSize" context:&kObservingContentSizeChangesContext];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if (context == &kObservingContentSizeChangesContext) {
        UIScrollView *scrollView = object;
        NSLog(@"%@ contentSize changed to %@", scrollView, NSStringFromCGSize(scrollView.contentSize));
    } else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

Если это не сработает, вам может потребоваться выполнить метод setContentSize:. Метод swizzling позволяет методу замещения вызывать оригинальный метод, который вам нужно сделать, чтобы передать новый размер содержимого в прокрутку.

Подробнее о методах swizzling вы можете прочитать здесь: http://www.mikeash.com/pyblog/friday-qa-2010-01-29-method-replacement-for-fun-and-profit.html

Я думаю, что это самый популярный код для swizzling: https://github.com/rentzsch/jrswizzle

Ответ 2

Ваш подход наполовину правильный. Вы, безусловно, можете переопределить существующий метод через категорию, чего вы не можете сделать, хотя и обращаетесь к ivar класса.

В этом случае вам нужен метод swizzling: вы переопределяете setContentSize и в то же время сохраняете ссылку на исходную реализацию метода, поэтому вы можете вызвать его, чтобы установить значение _contentSize.

Вот код, который вы могли бы использовать, с комментариями:

@implementation UIScrollView (Height)

// -- this method is a generic swizzling workhorse
// -- it will swap one method impl with another and keep the old one
// under your own impl name
+ (void)swizzleMethod:(SEL)originalSel andMethod:(SEL)swizzledSel {

  Method original = class_getInstanceMethod(self, originalSel);
  Method swizzled = class_getInstanceMethod(self, swizzledSel);
  if (original && swizzled)
     method_exchangeImplementations(original, swizzled);
  else
    NSLog(@"Swizzling Fault: methods not found.");

}    

//-- this is called on the very moment when the categoty is loaded
//-- and it will ensure the swizzling is done; as you see, I am swapping
//-- setContentSize and setContentSizeSwizzled;
+ (void)load {
  [self swizzleMethod:@selector(setContentSize:) andMethod:@selector(setContentSizeSwizzled:)];
}

//-- this is my setContentSizeSwizzled implementation;
//-- I can still call the original implementation of the method
//-- which will be avaiable (*after swizzling*) as setContentSizeSwizzled
//-- this is a bit counterintuitive, but correct!
- (void)setContentSizeSwizzled:(CGSize)contentSize
{
  [self setContentSizeSwizzled:contentSize];
  [[NSNotificationCenter defaultCenter] postNotification:[NSNotification    notificationWithName:@"scrollViewContentSizeChanged" object:nil]];
}

@end

Надеюсь, что это поможет.