gpt4 book ai didi

ios - 为 UIView 提供数据

转载 作者:行者123 更新时间:2023-12-01 16:37:50 25 4
gpt4 key购买 nike

假设你有一个 UIView显示来自某个模型对象的数据。当模型在后台发生变化时,它会通过某种订阅机制通知其监听器;一个很常见的模式...

我在 iOS 上一直在做的是订阅 ViewControllers 中的模型通知。 viewWillAppear ;刷新相应的 View 以响应更改通知;并在 viewWillDisappear 中停止我的订阅.这样,当给定的 View Controller 离开屏幕时,通过跟踪更改来确保我不会浪费资源,所以我对这个解决方案很满意。

但是,我当前的项目需要一些 View 来跟踪模型对象,并且它们在多个 View Controller 中到处使用。如果我使用以前的方法,那么订阅/取消订阅管道将不得不在许多 View Controller 中复制。我想知道,这种逻辑是否可以放在 View 本身中?虽然 UIView's生命周期事件(willMoveToSuperview: 和 willMoveToWindow:) 在这方面有一些模糊的语义,这必须是可能的,因为这就是 Apple 对 iAd 显示 View 所做的 - 即 ADBannerView 不需要任何管道来开始显示广告,除了放置它在您的 View 层次结构中,并且它从远程源中提取数据,因此它不能通过对 iAd 服务器进行不必要的订阅来浪费资源。
有没有人做过这件事? IE。将昂贵的变更跟踪机制与 UIView 可靠地耦合在一起生命周期事件?

最佳答案

尽管使用 viewDidAppear,但我经常使用此过程因为我不能确定其他 View Controller 不会调用 viewWillAppear在当前的 viewWillDisappear 之前将被调用,当您将委托(delegate)分配给某个“共享实例”时,这可能会带来不便。

无论如何,我总是使用 View Controller 来处理这种重新加载,然后调用特定的 View 进行刷新。我在 removeFromSuperView 中退订了一些特定情况。方法,但您可以理解这不是最好的方法,因为 View 可以作为 subview 再次添加到某个 View 中,并且订阅不会自动完成。但话又说回来,在 View 本身由于订阅而自我保留的情况下,我确实使用了这个,最常见的情况是使用计时器或显示链接(这可以再次通过使用 2 个类来避免,但这是另一回事)。

如果在 View Controller 级别上使用此订阅/取消订阅,例如检查 View 是否确实可见,我建议您将其保留在那里并手动订阅/取消订阅 View Controller 拥有的 View 。如果没有其他原因,您的代码将更易于管理。

另一方面,如果这需要在某些特定 View 类型的级别上(创建一个库甚至只是简单地重用),那么我会尝试在某些 init 中处理这个问题。和 dealloc方法。同样,如果资源紧张,我会将逻辑移至 View Controller 。

无论如何,如果您找到一个可靠的解决方案,将这个逻辑严格地放在 View 中,我会很高兴听到它。

编辑评论以添加自保留解决方案:

当涉及到一个类被订阅保留的问题时,例如计时器或通知中心,您所做的是创建 2 个类。一个代表您的接口(interface)并具有获取特定数据所需的所有方法,并且如果需要包含调用者可以订阅的委托(delegate)(具有弱链接),我们将其称为 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 之外使用它一点也不。现在使用此过程,您可以添加任何方法、委托(delegate)或来自 classA 的任何内容。处理事件。

关于ios - 为 UIView 提供数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26605566/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com