2011-04-10 38 views
21

我正在尋找一種通知方式,以便在可視視圖層次結構中添加或刪除泛型UIView時得到通知。在這種情況下,KVO看起來像是完美的東西,但觀察對視圖的窗口或超級視圖屬性的更改不會執行任何操作。如框架或backgroundColor屬性的變化按預期方式工作,但更改爲與視圖層次結構有關的屬性似乎並沒有調用observeValueForKeyPath。觀察對UIView窗口和超級視圖屬性的更改

我通過調用自動NotNotifyObserversForKey來查看UIView是否支持這些屬性上的KVO,並且UIView對兩者都報告YES,從而使我不知所措。所以我的問題是:

1)有沒有辦法使用KVO來通知有關視圖被添加/刪除到視圖層次結構的事件?

2)如果沒有,是否有另一種方式來通知這種事件,不涉及UIView子類?

+0

嘗試以下信息,使用KVO結果:'志願autonotifying只支持-set :返回void的方法。 autonotifying不會被調用 - [WebView _setSuperview:]。我想知道是否有更好的方法來做到這一點,但我還沒有找到任何。 : -/ – nomothetis 2011-12-13 15:09:57

回答

9

這是一種方法。這是毛病嗎?是。我建議這樣的行爲?不,但我們都是大人。

要點是你使用method_setImplementation來改變 - [UIView didAddSubview:]的實現,這樣你就可以在被調用時得到通知(並且你會爲willRemoveSubview做同樣的事情:)。不幸的是,你會被調用所有視圖層次結構的變化。你必須添加自己的過濾,以找到你感興趣的具體意見

static void InstallAddSubviewListener(void (^listener)(id _self, UIView* subview)) 
{ 
    if (listener == NULL) 
    { 
     NSLog(@"listener cannot be NULL."); 
     return; 
    } 

    Method addSubviewMethod = class_getInstanceMethod([UIView class], @selector(didAddSubview:)); 
    IMP originalImp = method_getImplementation(addSubviewMethod); 

    void (^block)(id, UIView*) = ^(id _self, UIView* subview) { 
     originalImp(_self, @selector(didAddSubview:), subview); 
     listener(_self, subview); 
    }; 

    IMP newImp = imp_implementationWithBlock((__bridge void*)block); 
    method_setImplementation(addSubviewMethod, newImp); 
} 

要使用,這樣做:由道格@理查森

InstallAddSubviewListener(^(id _self, UIView *subview) { 
    NSLog(@"-[UIView didAddSubview:] self=%@, view=%@", _self, subview); 
}); 
+2

那麼,因爲沒有理智的答案很可能會出現,並且這個建議太骯髒,不配得到某種獎品,我會接受這個 – Mattia 2012-04-11 00:55:23

+1

它很醜,很漂亮。 – danh 2013-03-11 14:35:51

3
基於代碼

爲什麼不是一個讓KVO成爲superview地產的小清潔工?

//Make views announce their change of superviews 
    Method method = class_getInstanceMethod([UIView class], @selector(willMoveToSuperview:)); 
    IMP originalImp = method_getImplementation(method); 

    void (^block)(id, UIView*) = ^(id _self, UIView* superview) { 
     [_self willChangeValueForKey:@"superview"]; 
     originalImp(_self, @selector(willMoveToSuperview:), superview); 
     [_self didChangeValueForKey:@"superview"]; 
    }; 

    IMP newImp = imp_implementationWithBlock((__bridge void*)block); 
    method_setImplementation(method, newImp); 
+2

你測試過了嗎?我不清楚在你調用didChangeValueForKey的時候superview會被更新爲新值:@「superview」。 – 2013-03-11 18:30:19

7

重寫此方法:

- (void)didMoveToSuperview 
{ 
    UIView *superView = [self superview]; 
} 

而且可以覆蓋在其他使用自定義視圖這些方法:

- (void)willMoveToSuperview:(UIView *)newSuperview; 
- (void)didMoveToSuperview; 
- (void)willMoveToWindow:(UIWindow *)newWindow; 
- (void)didMoveToWindow;