我在某处读到,如果我在我的应用程序中有代表,我应该对它们保持弱引用 然而,当我调试应用程序时,应用程序不想继续,当我呼吁代表 因为我的代表在到达该方法时已被解除分配
为什么?
如果我把引用变为“强大”,一切正常,但我不确定这对我的内存分配有什么影响,以及这些代表不在“sharedInstance”类中的事实....
代码:
@interface LoginProcessListener()
@property (nonatomic,weak)id<UserSettingsDelegate>userSettings;
@property (nonatomic,weak)id<DisclaimerDelegate>disclaimerDelegate;
@end
@implementation LoginProcessListener
-(instancetype)initWithUserSettings:(id<UserSettingsDelegate>)userSettings andDisclaimerDelegate:(id<DisclaimerDelegate>)disclaimerDelegate{
self = [super init];
if (self){
[self setUserSettings:userSettings];
[self setDisclaimerDelegate:disclaimerDelegate];
}
return self;
}
-(void)onLoginAuthenticationProcessFinished{
User *user = [_userSettings getUserDetails];
if(user && [_disclaimerDelegate isConfirmedDisclaimer:[user disclaimerInfo]]){
[_disclaimerDelegate confirmedDisclaimer];
}else {
[_disclaimerDelegate needDisplayDisclaimer];
}
}
-(void)onLoggedInUserDetailsReceived:(User *)user{
[_userSettings saveUserDetails:user]; <== here my _userSettings is already nil;
}
答案 0 :(得分:1)
当我调试应用程序时,应用程序不想继续,当我调用委托时,因为我的委托已经在它到达该方法时被释放
但这是你的错误,你必须追查。代表的全部意义在于,您必须不允许它在其代表所在的事物之前死亡。一般来说,如果一个代表在另一个事情发生之前去世,那么你做错了什么;只要需要,代表的工作就是生活。
另一方面(总有一个&#34;另一只手&#34;)你所谓的委托可能不是真正的委托。如果它是一个主要存在自己的对象,它或多或少是一个委托。如果它只是一个值包或一个纯粹的辅助对象,其唯一目的是与保持对它的引用的对象相关联,那么它不是委托,强引用是正确的。
答案 1 :(得分:0)
你的架构是错误的。它应该是:
@interface UserSettings
@property (nonatomic,weak)id<UserSettingsDelegate>userSettingsDelegate;
@end
@interface Disclaimer
@property (nonatomic,weak)id<DisclaimerDelegate>disclaimerDelegate;
@end
实际上你的userSettings不是真正的委托,它只是LoginProcessListener的成员,所以你可以使用强引用。
通常id<UserSettingsDelegate>
创建UserSettings
并在其上创建自己的引用。如果UserSettings
将在id<UserSettingsDelegate
拥有引用,那么将会保留循环。
答案 2 :(得分:0)
当我调试应用程序时,应用程序不想继续,当我打电话给 委托,因为我的代表已被解除分配 它达到了那个方法
您在寻找的是一个弱定义属性的行为方式。
因为弱引用不会使对象保持活动状态,所以引用它是可能的 在引用仍在使用时要释放的对象。避免危险 悬挂指向最初由现在释放的对象占用的内存,一个弱点 当对象被解除分配时,引用自动设置为nil。
简单地说,如果不再分配代表,那么它将在其他地方发布。 的
话虽如此,你的bug根本不存在,但在其他地方。您将不得不回溯_userSession
来验证它的创建位置以及哪些对象具有强引用权。
答案 3 :(得分:0)
允许使用对代理的强引用,但是您需要了解正在发生的事情,因为它有您应该注意的风险。
Apple的文档掩盖了这一点,只是说委托用户保持与代表的弱链接,一般情况下这是真的,但有些情况,你的可能是其中之一,保持有意义强烈的参考。通常,这发生在异步代码中,否则代理可能会在使用之前被释放。
挥手太多:这是一个具体的例子。 NSURLConnection需要委托来执行异步IO。为了使其可靠并大大简化其使用,NSURLConnection只要需要,就会保留对其委托的强引用。以下是NSURLConnection文档的引用: -
“注意:在请求期间,连接保持对其委托的强引用。当连接完成加载,失败或被取消时,它会释放该强引用”
简单来说,在ARC下,“发布强引用”可能意味着将属性设置为nil。
摘要:如果您知道自己在做什么,请在必要时使用强引用,并记录好以便下一个看到该代码的人理解您为什么这样做。
答案 4 :(得分:0)
你可以对委托对象进行强有力的引用,这很酷的是NSURLConnectionDelegate协议所做的事情。我是这样做的:
我们说我有一个下载图像的协议。
@implementation AsyncImageLoadManager <NSURLConnectionDelegate>
static char delegateStrongReferenceKey;
.......
-(void)startDownload {
....
objc_setAssociatedObject(self, &delegateStrongRefernceKey, _delegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
_imageConnection = [NSURLConnection connectionWithRequest:request delegate:self];
objc_setAssociatedObject(self, &delegateStrongRefernceKey, _delegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
_downloadTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ //I use tihs instead of [connection start]; so that download continues if app goes to background
[_imageConnection cancel];
[[UIApplication sharedApplication] endBackgroundTask:_downloadTaskID];
_downloadTaskID = UIBackgroundTaskInvalid;
objc_setAssociatedObject(self, &delegateStrongRefernceKey, nil, OBJC_ASSOCIATION_ASSIGN);
}];
}
..../// and in connectionDidFinishLoading and connectionDidFailWithError you release the strong reference with:
[[UIApplication sharedApplication] endBackgroundTask:_downloadTaskID];
_downloadTaskID = UIBackgroundTaskInvalid;
objc_setAssociatedObject(self, &delegateStrongRefernceKey, nil, OBJC_ASSOCIATION_ASSIGN);