Ios 向UIView提供数据
假设您有一个显示来自某个模型对象的数据的Ios 向UIView提供数据,ios,iphone,ipad,uiview,Ios,Iphone,Ipad,Uiview,假设您有一个显示来自某个模型对象的数据的UIView。当模型在后台发生变化时,它通过某种订阅机制通知其侦听器;一个很常见的模式 我在iOS上所做的是订阅视图控制器中的模型通知视图将出现;刷新相应视图以响应更改通知;而在视图中停止订阅将消失。这样,当给定的视图控制器离开屏幕时,我就可以确保跟踪更改不会浪费资源,所以我对这个解决方案很满意 但是,我当前的项目需要一些跟踪模型对象的视图,这些视图在多个视图控制器中随处可见。如果我使用前面的方法,那么订阅/取消订阅管道必须在许多视图控制器中重复。我想知道
UIView
。当模型在后台发生变化时,它通过某种订阅机制通知其侦听器;一个很常见的模式
我在iOS上所做的是订阅视图控制器中的模型通知
视图将出现
;刷新相应视图以响应更改通知;而在视图中停止订阅将消失
。这样,当给定的视图控制器离开屏幕时,我就可以确保跟踪更改不会浪费资源,所以我对这个解决方案很满意
但是,我当前的项目需要一些跟踪模型对象的视图,这些视图在多个视图控制器中随处可见。如果我使用前面的方法,那么订阅/取消订阅管道必须在许多视图控制器中重复。我想知道,这个逻辑是否可以放在视图本身中?尽管UIView的
生命周期事件(willMoveToSuperview:和willMoveToWindow:)在这方面的语义有些模糊,但这必须是可能的,因为苹果公司在iAd显示视图中就是这么做的——即ADBannerView不需要任何管道来开始显示广告,只需将其放在视图层次结构中,而且它是从远程源引入数据,因此它不能因为对iAd服务器进行不必要的订阅而浪费资源。
有人做过这件事吗?也就是说,可靠地将昂贵的更改跟踪机制与
UIView
生命周期事件耦合起来?尽管使用了viewdidappease
,但我还是经常使用此过程,因为我无法确定在当前视图的视图消失之前,其他视图控制器是否会调用viewwillappease
将被调用,当您将委托分配给某个“共享实例”时,这可能会给您带来不便
无论如何,我总是使用视图控制器来处理此重新加载,然后调用特定视图进行刷新。在一些特定情况下,我使用removeFromSuperView
方法取消订阅,但您可以理解,这不是最好的方法,因为视图可以作为子视图再次添加到某些视图中,并且订阅不会自动完成。但我还是会在视图本身由于订阅而自保留的情况下使用它,最常见的情况是使用计时器或显示链接(使用2个类也可以避免这种情况,但这是另一回事)
如果在视图控制器级别使用此订阅/取消订阅来检查视图是否确实可见,我建议您将其保留在那里,并手动订阅/取消订阅视图控制器拥有的视图。如果没有其他原因,您的代码将更易于管理
另一方面,如果这需要在某个特定视图类型的级别上(创建一个库,甚至只是重用),那么我将尝试在一些init
和dealoc
方法中处理这个问题。同样,如果资源紧张,我会将逻辑移到视图控制器
在任何情况下,如果你找到一个可靠的解决方案,把这个逻辑严格地放在这个观点上,我会很高兴听到它
编辑注释以添加自保留解决方案:
当一个类被订阅(如计时器或通知中心)保留时,您要做的是创建两个类。其中一个表示您的接口,具有获取特定数据所需的所有方法,如果需要,它包含调用者可以订阅的委托(具有弱链接),我们将其称为class a。现在,该类包含另一个类,该类包含对外部源(如notification center)的实际订阅,并且是自保留的,B类。因此A类不是自保留的,因为它没有直接订阅通知中心、计时器。。。这意味着类A将被正确释放,而类B将持续存在并导致潜在的内存泄漏。然后,类B确实需要一个显式调用来取消订阅,因此它被释放,这应该在类Adealloc
方法中完成
我想简单的解释可能有点复杂,所以请看以下代码:
#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
#导入“ClassA.h”
@甲级;
@B类;
@协议类BDelegate
-(作废)ClassB平:(ClassB*)发送方;
@结束
@接口ClassB:NSObject
@属性NSTimer*计时器;
@属性(弱)id委托;
-(无效)欺诈处理;
-(无效)终止通知处理;
@结束
@实现类B
-(无效)beginNotificationHandling{
if(self.timer==nil){
self.timer=[NSTimer scheduledTimerWithTimeInterval:10.0目标:自选择器:@selector(onTimer)userInfo:nil repeats:YES];
}
}
-(无效)结束通知处理{
[自动定时器失效];
self.timer=nil;
}
-(void)onTimer{
[self.delegate classBPing:self];
}
@结束
@接口ClassA()
@财产类别B*类别B实例;
@结束
@实现类A
-(instancetype)初始化{
if((self=[super init])){
self.classBInstance=[[ClassB alloc]init];
self.classbinInstance.delegate=self;
[self.classBInstance beginNotificationHandling];
}
回归自我;
}
-(无效)解除锁定{
//一旦这个类被释放,classB实例就必须失效,这样它也会被释放
[self.classbinInstance endNotificationHandling];
}
-(无效)ClassB ping:(ClassB*)发送方{
NSLog(@“Ping”);
}
@结束
注意:这只是源文件,不需要在头文件中包含classB
,因为您根本不应该在classA
之外使用它。现在,使用此过程,您可以从classA
添加任何方法、委托或任何内容来处理事件。Init和dealloc在订阅保留订户时会出现问题(例如NSNotificationCenter