2012-12-13 7 views
8

Otrzymaliśmy projekt OGROMNY z outsourcingu, który staramy się "naprawić". W projekcie są setki kontrolerów widoku. Naszym celem jest łatwe określenie, na którą klasę aktualnie patrzymy na urządzeniu.Zapisywanie nazwy klasy wszystkich UIViewControllers w projekcie

Nasze rozwiązanie (które nie działało, stąd pytanie SO).

Zastąpić metodę viewDidAppear z UIViewController poprzez kategorii z tego:

-(void)viewDidAppear:(BOOL)animated 
{ 
    NSLog(@"Current View Class: %@", NSStringFromClass(self.class)); 
    [self viewDidAppear:animated]; 
    //Also tried this: 
    //[super viewDidAppear:animated]; 
} 

Ta kategoria będzie umieścić w .pch projektu.

Nie wymagałoby to dodatkowego kodu, który można umieścić w setkach kontrolerów View i można łatwo włączać i wyłączać. To nie działa, ponieważ, jak nauczyliśmy się teraz, < meme> jeden nie wystarczy zastąpić istniejący sposób poprzez kategorii < /mem>.

Czego nam brakuje?!?

+0

Ten kod ma nieskończoną pętlę, prawda?Powinieneś zadzwonić [super viewDidAppear: animated]; –

+0

@BrunoDomingues, ponieważ jest to kategoria na UIViewController, wywołanie super wywołałoby viewDidAppear na NSObject (nadklasę UIViewController), która nie istnieje. – adamweeks

+0

Można znaleźć bieżący widoczny widok (kontroler widoku) z UIWindow rootViewController. – 9dan

Odpowiedz

14

Odpowiedź brzmi: zawikłać metody! Oto co wymyśliliśmy:

#import "UIViewController+Logging.h" 
#import <objc/runtime.h> 

@implementation UIViewController (Logging) 

-(void)swizzled_viewDidAppear:(BOOL)animated 
{ 
    NSLog(@"Current View Class: %@", NSStringFromClass(self.class)); 
    [self swizzled_viewDidAppear:animated]; 
} 

+ (void)load 
{ 
    Method original, swizzled; 

    original = class_getInstanceMethod(self, @selector(viewDidAppear:)); 
    swizzled = class_getInstanceMethod(self, @selector(swizzled_viewDidAppear:)); 

    method_exchangeImplementations(original, swizzled); 

} 
@end 
+0

Używałem tego dzisiaj i jest jedna "gotcha", z którą się zetknęliśmy. Jeśli podklasa wywoła viewDidAppear, ale nie wywoła [super viewDidAppear], nie otrzymasz dziennika. – adamweeks

+0

Właśnie natknąłem się na to. Dla dobra innych czytających komentarze, wszystkie podklasy UIViewController MUSZĄ wywołać [super viewDidAppear], więc jeśli tego brakuje, jest to inny błąd programisty. – Shinigami

1

Czy kontrolery widoku mają wspólną klasę podstawową? jeśli tak, możesz umieścić go tam w klasie podstawowej "implementacja [viewDidAppear:]. Jeśli nie mają wspólnej bazy, być może byłoby to warte zachodu, ponieważ przydałby się i tak dalej (wspólny kod analityczny itp.).

+0

Niestety nie. Wszystkie są po prostu podklasami UIViewController. Patrząc na metodę swizzling dla rozwiązania. – adamweeks

+0

Wiem, że masz setki kontrolerów, ale dobre znajdowanie/zamiana może łatwo pomóc ci dziedziczyć ze zwykłej klasy kontrolera. To sprawi, że to konkretne zadanie będzie łatwe i przyniesie inne korzyści. –

0

Można zrobić to aplikacja szeroki znaleźć i zamienić z Xcode, ale niekoniecznie będzie znaleźć każdy przypadek (ale ani to czy podejścia, że ​​próbowałeś). Możesz szukać "[super viewDidLoad];" i zamień na "[super viewDidLoad]; NSLog (@" Current View Class:% @ ", NSStringFromClass (self.class));"

+0

Poszukuje prostszego rozwiązania, które będzie działało w całej aplikacji, zamiast modyfikować każdą klasę zgodnie z opisem w pytaniu. – adamweeks

3

Oto rozwiązanie tego

w pliku .pch obejmują ten

#define UIViewController MyViewController 
#import "MyViewController.h" 

Utwórz nową klasę UIViewController sub jak

.h pliku

#import <UIKit/UIKit.h> 

#ifdef UIViewController 
#undef UIViewController 
#endif 
@interface MyViewController : UIViewController 

@end 
#ifndef UIViewController 
#define UIViewController MyViewController 
#endif 

oraz. plik m

#import "MyViewController.h" 

@implementation MyViewController 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    NSLog(@"Current View Class: %@", NSStringFromClass(self.class)); 
} 

@end 
+0

Po prostu mam okazję przetestować ten kod i działa również. Czy ta metoda ma jakieś zalety/wady w porównaniu do metody swizzling? – adamweeks

+0

To, co robi mój kod, polega na tym, że zastępuje super klasę 'UIViewController' na' MyViewController'. Nie mogłem znaleźć żadnych niedogodności dla obu podejść teraz .. –

+0

Dzięki za rozwiązanie, wciąż czekasz na dalsze informacje, zanim przyjmiesz odpowiedź. – adamweeks

0

Czy aplikacja używa kontrolerów nawigacji do wyświetlania kontrolerów widoku? Jeśli tak, możesz użyć metod NavigationController do zgłaszania bieżącego kontrolera:

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated 
    { 
     [self reportNewController:viewController]; 
    } 

    - (void) reportNewController:(UIViewController *)viewController 
    { 
     NSString *name = viewController.title; 
      NSLog(@"Name is %@",name); 
    } 
Powiązane problemy