Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/39.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 向UIView提供数据_Ios_Iphone_Ipad_Uiview - Fatal编程技术网

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确实需要一个显式调用来取消订阅,因此它被释放,这应该在类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
#导入“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