2012-11-08 28 views
12

Tôi đang cố gắng đặt UIView ở cuối nội dung của UIScrollView, làm như vậy tôi đặt vị trí của chế độ xem thành hình ảnh của scrollview. Nhưng scrollview của tôi là một subview của một UIWebView vì vậy khi hình ảnh được tải, nội dung thay đổi heigth và xem của tôi mà nên ở dưới cùng của scrollview kết thúc ở giữa ...phát hiện các thay đổi đối với nội dung của chế độ xem cuộn của UIWebViewKích thước

Vì vậy, tôi đang tìm kiếm một cách được thông báo khi nội dung của scrollview thay đổi. Tôi đã cố gắng để phân lớp nó và thay đổi setter cho contensize để gửi một NSNotification:

@implementation UIScrollView (Height) 

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

@end 

Nhưng trên biên dịch tôi nhận được và báo lỗi nói:

"_OBJC_IVAR _ $ _ UIScrollView._contentSize", tham chiếu từ : - [UIScrollView (Heigth) setContentSize:] trong MyClass.o ld: biểu tượng (s) không tìm thấy cho kiến ​​trúc ARMv7

Bất kỳ ý tưởng như thế nào setter nên được subclassed?

Cảm ơn!

Trả lời

28

Có lẽ bạn có thể sử dụng quan sát giá trị quan trọng (KVO) để phát hiện các thay đổi đối với kích thước nội dung. Tôi đã không thử nó, nhưng mã sẽ giống như thế này:

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]; 
    } 
} 

Nếu điều đó không làm việc, bạn có thể cần phải sự gian lận phương pháp setContentSize:. Phương thức swizzling cho phép phương thức thay thế của bạn gọi phương thức ban đầu, đó là những gì bạn cần làm để chuyển kích thước nội dung mới vào chế độ xem cuộn.

Bạn có thể đọc thêm về phương pháp swizzling đây: http://www.mikeash.com/pyblog/friday-qa-2010-01-29-method-replacement-for-fun-and-profit.html

Tôi nghĩ rằng đây là mã phổ biến nhất cho swizzling: https://github.com/rentzsch/jrswizzle

+0

cảm ơn vì đã chỉ ra lỗi của tôi. đã xóa câu trả lời :) –

+1

KVO hoạt động như một sự quyến rũ, cảm ơn bạn rất nhiều! – Abel

+0

@rob mayoff bạn có thể chia sẻ, điều này trên swift3? –

3

cách tiếp cận của bạn là một nửa chính xác. Bạn chắc chắn có thể ghi đè lên một phương pháp hiện có thông qua một thể loại, những gì bạn không thể làm, mặc dù đang truy cập một ivar của lớp.

Trong trường hợp này, những gì bạn cần là phương pháp nổi bật: bạn ghi đè setContentSize trong khi đồng thời giữ tham chiếu đến việc triển khai thực hiện ban đầu của phương pháp, vì vậy bạn có thể gọi nó để đặt giá trị _contentSize.

Dưới đây là đoạn code mà bạn có thể sử dụng, với nhận xét:

@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 

Hy vọng nó giúp.

+0

Cảm ơn bạn rất nhiều vì câu trả lời hay này. Nhưng tôi có một câu hỏi. Nếu tôi có nhiều trường hợp cho đối tượng, làm thế nào tôi có thể phát hiện cá thể nào đang gọi phương thức này? –

+0

@ OlcayErtaş: bạn có thể sử dụng 'postNotificationName: object: userInfo:' và gửi 'self' là' userInfo' hoặc bất kỳ thông tin hữu ích nào khác: https://developer.apple.com/reference/foundation/nsnotificationcenter/1410608-postnotificationname? language = objc – sergio

+0

Tôi cũng làm như vậy. Cảm ơn bạn đã phản hồi. –

Các vấn đề liên quan