【问题标题】:setting delegate in a subview to nil将子视图中的委托设置为 nil
【发布时间】:2011-05-30 05:53:09
【问题描述】:

假设我有一个 UIViewController。在那个 UIViewController 里面我有一个 UITextView。 在 viewDidLoad 中,我将 UITextView 的委托设置为 self。这意味着我需要在dealloc中做textview.delegate = nil?这是真的?有人可以用外行的方式解释为什么会这样吗?

如果我误解了“在调用 [super dealloc] 之前释放 UIViewController 但未将子视图委托设置为 nil”的概念,那么有人可以给我一个示例

一个真正错误的例子:(澄清)

CreateGroupViewController * cgvc = [[CreateGroupViewController alloc] init];
    cgvc.delegate = self;
    UINavigationController * uinc = [[UINavigationController alloc] initWithRootViewController:cgvc];
    uinc.navigationBar.tintColor = [UIColor blackColor];
    uinc.modalPresentationStyle = UIModalPresentationFormSheet;
    [self presentModalViewController:uinc animated:YES];
    cgvc.delegate = nil;    
    [cgvc release];

我的意思是,说每次释放对象时最好将委托设置为 nil 是不正确的。在这种情况下,我展示了一个 ModalViewController。但是,在执行委托之前,我已经取消了委托,因此它没有执行。现在你怎么解释这个?

【问题讨论】:

    标签: iphone objective-c


    【解决方案1】:

    是的,这是解决此问题的正确方法。将委托设置为对象后,实际上是将委托分配给该特定对象,这是在释放它之前将其设置为 nil 的理想方法。

    【讨论】:

    • 另一个问题是,将某个对象的委托设置为 nil 不必在 dealloc 中对吗?是在我释放对象之前?我很少看到这种做法
    • 是的,在您释放对象之前。在你的情况下,我猜它必须是 dealloc 因为你的视图控制器的对象将被 dealloc 释放
    • 在释放对象之前将其设置为nil 是荒谬的。调用 [nil release] 实际上什么也没做。
    • @Josh:我不是说在发布之前将对象设置为 nil。我说过在释放对象之前将对象的委托设置为 nil
    • 这也没有意义:obj.ivar = nil; [obj release];?当对象被释放时,ivar 将被销毁。
    【解决方案2】:

    是的,您应该在完成后将委托设置为 nil。如果在委托对象释放后尝试调用委托对象上的方法,这可以防止应用程序崩溃。 (请记住,向 nil 对象发送消息是完全合法的)。

    更多详情请访问Should you set the delegate to nil in the class using the delegate or in the class itself

    【讨论】:

    • 所以应该在我释放它之前将代理设置为 nil 吗?所以我需要做 viewcontroller.delegate = nil 然后 viewcontroller 释放。对吗?
    • 我很少看到有人这样做,所以说我有一个 UITableView,通常人们会做 tableView.delegate = self.但我很少看到人们在他们的 dealloc 中做 tableView.delegate = nil
    • 通读我提供的链接上的答案/cmets,了解有关为什么要这样做的更多详细信息。
    • @Josh Caldwell - 我不认为这就是@aherlambang 的意思。如果你有 a.delegate = self,你要确保在释放 a 之前将 a.delegate 设置为 nil,对吧?
    • 我绝对有可能误解了这个问题(这就是我删除评论的原因)。但是,obj.ivar = nil; [obj release]; 似乎也没有任何意义,因为 obj 即将被销毁,在这种情况下,它的 ivar 也会被销毁,或者您正在销毁您没有所有权的 ivar。
    【解决方案3】:

    更新解决您的 sn-p:

    CreateGroupViewController * cgvc;
    cgvc = [[CreateGroupViewController alloc] init];
    // We now _own_ cgvc; we are responsible for its memory
    cgvc.delegate = self;    // cgvc will send us some fun messages
    
    cgvc.delegate = nil;     // Not necessary, because:
    [cgvc release];          // cgvc no longer exists
    

    唯一有意义的情况是,如果作为委托的对象(称为A)被释放之前被其委托的对象(称为B)。例如,如果 B 是一个文本字段,则可能会发生这种情况。 A 消失后,文本字段会一直存在,我们不希望 B 尝试向已释放的 A 发送消息:

    MyDelegateClass * del = [[MyDelegateClass alloc] init];
    myLongLivedObjThatNeedsADelegate.delegate = del;
    
    // Do stuff...
    
    // Release delegate object without setting outlet to nil
    [del release];
    
    // ----
    // Some time later, in myLongLivedObjectThatNeedsADelegate:
    [delegate objShouldDoX:self];  // CRASH! delegate points to 
                                   // deallocated instance
    

    如果变量中有对象,并且不再需要该对象,但该变量可能(不小心)稍后会被使用,则在释放对象后将变量设置为nil 是一种安全措施。

    演示:

    NSString * str1 = [[NSString alloc] init];
    NSString * str2 = [[NSString alloc] init];
    NSString * str3 = [[NSString alloc] init];
    
    str1 = nil;       // We just leaked the object that was at str1;
                      // there is no way to release it.
    [str1 release];   // Does nothing
    [str1 length];    // Also does nothing
    
    [str2 release];   // Release the object
    [str2 length];    // CRASH! message sent to deallocated instance
    
    [str3 release];
    str3 = nil;      // A safety measure
    [str3 length];   // Does nothing
    

    当您拥有属性和综合设置器时,它会变得更有趣。如果您有房产:

    @property (retain) NSString * myString;
    

    你合成了setter,setter看起来像这样:

    - (void) setMyString:(NSString *)newString {
        [newString retain];    // Take ownership of new object
        [myString release];    // Relinquish old object
        myString = newString;  // Rename new object
    }
    

    所以,如果你这样做self.myString = nil;,会发生什么相当于如下:

    [self setMyString:nil];
        // Inside setMyString: newString is nil
        [nil release];        // Does nothing
        [myString release];   // Relinquish old object
        myString = nil;       // Set myString to nil
    

    您会看到综合属性自动为您执行常规的“安全”实践。这就是为什么您可能会看到人们建议将属性设置为 nil

    最后要注意的是,在dealloc 中是否将ivar 设置为nil 并不重要,因为将不再使用该名称。拥有它的对象正在被破坏,因此“安全措施”不适用。因此,在dealloc,您可以轻松释放您的ivars。

    【讨论】:

    • 我可能误解了这个问题。
    • 澄清我上面的一个真正错误的例子......这实际上是让我感到困惑的地方
    • @aherlambang:完成;虽然我的其余帖子没有直接解决您的问题,但希望它可以帮助您了解背景。
    • @Josh 您说在发布之前设置 cgvc.delegate = nil 没有任何效果。我有点不同意这一点...在您的解释中,您没有将该视图控制器添加为 rootviewcontroller导航控制器.. 我认为这会有所不同
    • CreateGroupViewController 有一个文本框和一个按钮,它将委托消息发送回父视图控制器(呈现模式视图控制器的类),所以如果我在释放它之前将委托设置为 nil并且在释放它之前不将其设置为 nil 有两种不同的行为。如果我将委托设置为 nil,则父视图控制器将不会收到发送给它的消息(因为委托为 nil),如果我不这样做将其设置为 nil,然后它按预期的方式工作(父视图控制器获取发送给它的消息)
    猜你喜欢
    • 1970-01-01
    • 2011-09-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-06
    • 2017-12-11
    • 1970-01-01
    • 2017-09-08
    • 2010-11-07
    相关资源
    最近更新 更多