2014-10-28 4 views
2

Предположим, что у вас есть UIView, который отображает данные из какого-либо объекта модели. Когда модель изменяется в фоновом режиме, она уведомляет своих слушателей через какой-либо механизм подписки; довольно распространенный шаблон ...Подача UIView с данными

Что я делал в iOS, подписывается на уведомления о модели в ViewControllersviewWillAppear; обновление соответствующих мнений в ответ на уведомление об изменении; и прекратить мою подписку в viewWillDisappear. Таким образом, было гарантировано, что я не буду тратить ресурсы, отслеживая изменения, когда данный контроллер представления был вне экрана, поэтому я был доволен этим решением.

Однако моему текущему проекту нужны некоторые виды, которые отслеживают объект модели, и они используются повсеместно в нескольких контроллерах представлений. Если бы я использовал предыдущий подход, тогда сантехника для подписки/отмены подписки должна была бы дублироваться во многих контроллерах представлений. Мне было интересно, может ли эта логика быть поставлена ​​в самом представлении? Хотя события жизненного цикла UIView's (willMoveToSuperview: и willMoveToWindow :) имеют несколько неопределенную семантику в этом отношении, это должно быть возможно, так как это то, что Apple делает с видами отображения iAd - то есть, для ADBannerView не требуется никаких сантехнических работ для показа рекламы кроме того, что он помещается в иерархию вашего представления, и это данные pullin из удаленных источников, поэтому он не должен тратить ресурсы на ненужные подписки на серверы iAd. Кто-нибудь сделал это? То есть надежно связать дорогостоящие механизмы отслеживания изменений с событиями жизненного цикла UIView?

ответ

0

Я использую эту процедуру довольно часто, хотя с помощью viewDidAppear, так как я не могу быть уверен, что какой-либо другой контроллер представления не будет вызывать viewWillAppear до нынешней СВОЕЙ viewWillDisappear будет называться, и это может быть неудобство, когда вы назначаете делегат некоторые " общий экземпляр ".

В любом случае, я всегда использую контроллеры представлений для обработки этих перезагрузок, а затем вызываю определенные виды, которые нужно обновить. Было несколько конкретных случаев, когда я отказался от подписки в методе removeFromSuperView, но вы можете понять, что это не лучший подход, так как представление может быть снова добавлено в какое-то представление в качестве подзапроса, и подписка не выполняется автоматически. Но опять же я использую это в тех случаях, когда сам вид сам сохраняется из-за подписки, для которой наиболее распространенной ситуацией является использование таймера или ссылки на изображение (этого можно избежать, используя 2 класса, но это другое дело).

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

Если, с другой стороны, это должно быть на уровне определенного типа вида (создание библиотеки или даже просто повторное использование), тогда я попытался бы обработать это в некоторых случаях: init и dealloc. Опять же, если ресурсы жесткие, я бы переместил логику в контроллер вида.

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

Редактировать на комментарий, чтобы добавить само сохранить решение:

Когда дело доходит до вопроса, когда класс сохраняется по подписке, такие как таймер или уведомления центра, что вы делаете, это создать 2 класса ,Один представляет ваш интерфейс и имеет все методы, необходимые для получения конкретных данных, и при необходимости содержит делегата, которому абонент может подписаться (имея слабую ссылку), назовем его классом A. Теперь этот класс содержит другой класс, который содержит фактический подписки на внешние источники, такие как центр уведомлений, и самосохраняемый класс B. Таким образом, класс A не сохраняется самостоятельно, поскольку он не имеет прямых подписчиков в центре уведомлений, таймеры ... Это означает, что класс A будет освобожден должным образом, в то время как класс B будет сохраняются и вызывают потенциальную утечку памяти. Класс B тогда нуждается в явном вызове, который будет отменен, поэтому он будет выпущен, и это должно быть сделано в методе класса A dealloc.

Я думаю, простое объяснение может быть немного сложнее, так что смотреть на этот код:

#import "ClassA.h" 

@class ClassA; 
@class ClassB; 

@protocol ClassBDelegate <NSObject> 
- (void)classBPing:(ClassB *)sender; 
@end 

@interface ClassB : NSObject 
@property NSTimer *timer; 
@property (weak) id<ClassBDelegate> delegate; 
- (void)beginNotificationHandling; 
- (void)endNotificationHandling; 
@end 

@implementation ClassB 
- (void)beginNotificationHandling { 
    if(self.timer == nil) { 
     self.timer = [NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:@selector(onTimer) userInfo:nil repeats:YES]; 
    } 
} 
- (void)endNotificationHandling { 
    [self.timer invalidate]; 
    self.timer = nil; 
} 
- (void)onTimer { 
    [self.delegate classBPing:self]; 
} 

@end 

@interface ClassA()<ClassBDelegate> 
@property ClassB *classBInstance; 
@end 
@implementation ClassA 

- (instancetype)init { 
    if((self = [super init])) { 
     self.classBInstance = [[ClassB alloc] init]; 
     self.classBInstance.delegate = self; 
     [self.classBInstance beginNotificationHandling]; 
    } 
    return self; 
} 

- (void)dealloc { 
    // once this class is deallocated the classB instance must be invalidated so it is deallocated as well 
    [self.classBInstance endNotificationHandling]; 
} 

- (void)classBPing:(ClassB *)sender { 
    NSLog(@"Ping"); 
} 

@end 

отметить, что это только исходный файл, нет необходимости иметь classB в файле заголовка, как вы должны не используйте его за пределами classA. Теперь, используя эту процедуру, вы можете добавлять любые методы, делегаты или что-то еще от classA для обработки событий.

+0

Init и dealloc становятся проблематичными, когда подписка сохраняет подписчика (например, NSNotificationCenter делает это) –

+0

Да, поскольку я упоминал, что проблема возникает, когда у вас есть ситуация с сохранением себя, как вы только что упомянули. Позвольте мне отредактировать ответ, чтобы добавить это уже упомянутое «другое». –

+0

Попробуйте изучить эту процедуру (отредактировано) ... –

Смежные вопросы