简体   繁体   English

强烈推荐给代表

[英]strong reference to delegates

I read somewhere that if i have delegates in my app, i should keep a weak reference to them however, when i debug the app, the app doesnt want to move on, when i call on a delegate because my delegate has already been deallocated by the time it reached that method 我在某处读到,如果我的应用程序中有委托,我应该对它们保持弱引用,但是,当我调试应用程序时,当我调用委托时,该应用程序不想继续运行,因为我的委托已经被释放了。达到该方法的时间

why ? 为什么呢?

If i put the reference to be "strong" everything works just fine, though i am not sure what are the consequences of that on my memory allocations and the fact that those delegates are not in "sharedInstance" classes.... 如果我将引用设置为“强”,那么一切都很好,尽管我不确定这对我的内存分配有什么影响,以及那些委托不在“ sharedInstance”类中的事实。

code: 码:

    @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;
}

when i debug the app, the app doesnt want to move on, when i call on a delegate because my delegate has already been deallocated by the time it reached that method 当我调试应用程序时,应用程序不想继续运行,当我调用委托时,因为到达该方法时我的委托已被释放

But that is your bug, which you must track down. 但这是您的错误,必须对其进行跟踪。 The whole point of a delegate is that you must not permit it to die before the thing whose delegate it is. 委托人的全部要点是,您不得让其在委托人之前死亡。 In general, if a delegate dies before the other thing does, you are doing something wrong; 通常,如果一个代表在另一件事之前就去世了,那说明您在做错事。 it is the job of a delegate to live as long as it is needed. 只要有需要,代表的工作就是活下去。

On the other hand (there is always an "other hand") it may be that what you are calling a delegate is not really a delegate. 另一方面(总是有“另一只手”),可能是您所说的委托不是真正的委托。 It is a delegate more or less if it is an object with a primary existence of its own. 如果它是一个主要存在的对象,则它或多或少是一个委托。 If it's just a packet of values or a purely ancillary object whose only purpose is in connection with the object keeping a reference to it, then it is not a delegate and a strong reference is correct. 如果它只是值的数据包或纯粹的辅助对象,其唯一目的是与保留对其引用的对象有关,则它不是委托,而强引用是正确的。

Yours architecture is wrong. 您的架构是错误的。 It's should be: 应该是:

@interface UserSettings
@property (nonatomic,weak)id<UserSettingsDelegate>userSettingsDelegate;
@end

@interface Disclaimer
@property (nonatomic,weak)id<DisclaimerDelegate>disclaimerDelegate;
@end

Actually yours userSettings not real delegate, it just member of LoginProcessListener, so you may use strong references. 实际上,您的userSettings不是真正的委托,它只是LoginProcessListener的成员,因此您可以使用强引用。

Commonly id<UserSettingsDelegate> creates UserSettings and own reference on it. 通常, id<UserSettingsDelegate>创建UserSettings并拥有自己的引用。 If UserSettings will own reference at id<UserSettingsDelegate , then there will be retain loop. 如果UserSettings将拥有id<UserSettingsDelegate的引用,则将存在保留循环。

when i debug the app, the app doesnt want to move on, when i call on a delegate because my delegate has already been deallocated by the time it reached that method 当我调试应用程序时,应用程序不想继续运行,当我调用委托时,因为到达该方法时我的委托已被释放

What's your seeking is how a weakly defined property behaves. 您要寻找的是弱定义属性的行为方式。

Via the docs: https://developer.apple.com/library/ios/documentation/cocoa/conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html#/apple_ref/doc/uid/TP40011210-CH5-SW30 ) 通过文档: https : //developer.apple.com/library/ios/documentation/cocoa/conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html#/apple_ref/doc/uid/TP40011210-CH5-SW30

Because a weak reference doesn't keep an object alive, it's possible for the referenced object to be deallocated while the reference is still in use. 因为弱引用不能使对象保持活动状态,所以在引用仍在使用时,可能会释放所引用的对象。 To avoid a dangerous dangling pointer to the memory originally occupied by the now deallocated object, a weak reference is automatically set to nil when its object is deallocated. 为避免指向原来由现在已释放对象占用的内存的危险的悬空指针,当将其对象释放时,弱引用将自动设置为nil。

Simply put, if the delegate is no longer allocated, it's being released elsewhere. 简而言之,如果不再分配委托,它将在其他地方释放。

With that said, your bug is likely not there at all, but elsewhere. 话虽如此,您的错误可能根本不存在,而在其他地方。 You're going to have to backtrace _userSession to verify where it's being created and what objects have strong references to it. 您将必须回溯_userSession来验证它是在哪里创建的,以及哪些对象对其具有强引用。

Using a strong reference to a delegate is permissible, but you need to understand what is going on as it has risks that you should be aware of. 允许使用对委托的强引用,但是您需要了解正在发生的事情,因为它存在您应注意的风险。

Apple's documentation kind of glosses over this, just saying that delegate users keep a weak link to the delegate, and in general this is true, but there are cases, and yours may be one of them, where it makes sense to keep a strong reference. Apple的文档对此有所掩饰,只是说代理用户与代理之间的链接很薄弱,总的来说,这是对的,但是在某些情况下,您的例子可能就是其中之一,在这种情况下,保持强引用是有意义的。 In general, this happens in asynchronous code where the delegate might otherwise be released before it is used. 通常,这在异步代码中发生,在异步代码中,在使用委托之前,可能会释放委托。

Too much hand waving: here is a concrete example. 挥舞的手太多:这是一个具体示例。 NSURLConnection needs a delegate to do asynchronous IO. NSURLConnection需要委托来执行异步IO。 In order to make this reliable and to greatly simplify it's usage, NSURLConnection keeps a strong reference to it's delegate as long as it needs one. 为了使其可靠并大大简化其使用,只要需要,NSURLConnection都会强烈引用其委托。 Here is a quote from the NSURLConnection documentation :- 这是NSURLConnection文档的引文:

"Note: During a request, the connection maintains a strong reference to its delegate. It releases that strong reference when the connection finishes loading, fails, or is canceled" “注意:在请求期间,连接维护对其委托的强引用。当连接完成加载,失败或取消时,它将释放该强引用。”

In simple terms, under ARC, "releases that strong reference" probably means setting the property to nil. 简单来说,在ARC中,“释放强引用”可能意味着将属性设置为nil。

Summary: If you know what you're doing, use strong references when you have to, and document well so that the next person to see that code understands why you did it. 简介:如果您知道自己在做什么,请在需要时使用强大的引用,并记录良好,以便让下一个看到该代码的人理解您为什么这样做。

You can temoprarily make a strong reference to the delegate object, which is excatly what NSURLConnectionDelegate protocol does. 您可以临时性地对委托对象进行强有力的引用,这正是NSURLConnectionDelegate协议所做的事情。 I do it like this: 我这样做是这样的:

Let's say i have a protocol for downloading images. 假设我有一个下载图片的协议。

@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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM