我正在尝试在UIScrollView内容的底部设置一个UIView,这样做我将视图的位置设置为scrollview的contentsize高度。但是我的scrollview是UIWebView的子视图,因此当加载图像时,内容大小会发生变化,我应该位于scrollview底部的视图最终会在中间...
所以我正在寻找一种在scrollview的内容化更改时得到通知的方法。我试图将其子类化并更改contentize的setter以发送NSNotification:
@implementation UIScrollView (Height)
-(void)setContentSize:(CGSize)contentSize
{
_contentSize=contentSize;
[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:@"scrollViewContentSizeChanged" object:nil]];
}
@end
但是在编译时我得到并且错误地说:
“_ OBJC_IVAR _ $ _ UIScrollView._contentSize”,引自: - MyClass.o中的[UIScrollView(Heigth)setContentSize:] ld:找不到架构armv7的符号
知道如何将setter子类化吗?
谢谢!
答案 0 :(得分:29)
也许您可以使用键值观察(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:
方法。方法调配让你的替换方法调用原始方法,这是将新内容大小传递给滚动视图所需要做的。
您可以在此处详细了解方法调整:http://www.mikeash.com/pyblog/friday-qa-2010-01-29-method-replacement-for-fun-and-profit.html
我认为这是最流行的代码:https://github.com/rentzsch/jrswizzle
答案 1 :(得分:3)
你的方法是正确的。您可以通过类别覆盖现有方法,但不能访问类中的ivar。
在这种情况下,您需要的是方法调配:您覆盖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
希望它有所帮助。