`
jiava9900
  • 浏览: 87520 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论
阅读更多

    <p>http://pingguohe.net/2011/09/01/howtojudgewhetheradelegateisreleased/#comment-983</p>
<p>困惑了相当长时间的一个问题了,实际上在Xcode4中会出现?</p>
<p>if ((int)delegate-&gt;isa == classIsa) {?</p>
<p>这行报错,member reference base type 'id&lt;HTTPRequestDelegate&gt;' is not a structure or union</p>
<p>因为ide不认为它是NSObject对象,只要对它转为NSObject对象即可。</p>
<p>//************************************************************************************</p>
<p><span style="color: #333333; font-family: 'Trebuchet MS', Helvetica, Arial, Geneva, sans-serif; font-size: 22px; line-height: 26px;">Cocoa中回调delegate的方法时判断delegate是否已经被释放</span><span style="color: #333333; font-family: 'Lucida Grande', Verdana, Helvetica, Arial, Geneva, sans-serif; font-size: 13px; line-height: 20px;">
</span></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding: 0px;">这个需要是因为最近在做网络请求的底层,需要在请求完成时回调某delegate的某方法。<br style="padding: 0px; margin: 0px;">然而回调时经常遇到这种情况:delegate已经被release了。如果delegate已经被dealloc掉,则无法调用其方法,否则引起程序crash。</p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding: 0px;">此篇文章中博客作者也有相同的问题:<a style="color: #5371c5; text-decoration: none; padding: 0px; margin: 0px;" href="http://longtimenoc.com/archives/objective-c-delegate%E7%9A%84%E9%82%A3%E7%82%B9%E4%BA%8B%E5%84%BF">http://longtimenoc.com/archives/objective-c-delegate的那些事儿</a></p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding: 0px;">首先,我们此时无法用if (nil = delegate)判断delegate是否已经被dealloc掉,因为被dealloc之后,delegate对象也不是空的,大部分情况下是一个objc_object*类型的C指针。</p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding: 0px;">其次,我们又会想到在本对象中先对delegate retain一次,这样回调时不会崩溃了。但是这样会出现一个retain cycle,本对象和delegate都永远不会被释放了。</p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding: 0px;">再次,我想到是否可以用isKindOfClass判断是否被dealloc。然而此时也不能用[delegate isKindOfClass]判断是否已经被dealloc,因为isKindOfClass是NSObject协议中的方法,此时delegate如果不是NSObject,对其发送isKindOfClass消息会导致crash。</p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding: 0px;">此时很小部分情况下,delegate会是NSObject,可能是NSDictioary,也可能是原本的类。而大部分情况下,delegate已经不是NSObject。所以此时任何形式的[delegate method]都会导致crash,因为任何的[delegate method]的前提都是:delegate是一个NSObject。</p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding: 0px;">无奈之下我又想到,使用delegate-&gt;isa判断delegate是不是NSObject。这里介绍一下,objective-c中所有对象都是结构体,每个结构体中都有一个名为isa的指针指向其类。而类也是一种结构体,类的isa指向其父类。处于最底层的结构体是无isa的,NSObject的isa指向的也是NSObject。isa具体的值是运行时确定的。<br style="padding: 0px; margin: 0px;">一开始的思路是用delegate-&gt;isa-&gt;isa-&gt;isa-&gt;…一直指下去,如果isa与NSObject的isa相同,则说明delegate是一个NSObject。但是这样是行不通的,因为如果delegate不是NSObject,只是objc_object*,一直指下去却指不到NSObject的话,总会指到最底层的结构体,而此结构体无isa,如果访问结构体内没有的东西,程序又会crash了。</p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding: 0px;">说了这么多,结论就是这个问题很是蛋疼。再做不出来我就要把释放本对象的责任交给用户了。</p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding: 0px;">等等,如果在本对象初始化后,delegate传进来时保存delegate的isa,此时delegate一定未被dealloc(为什么?因为是单线程的),在回调时判断delegate此时的isa和当时保存的isa是否一样,就可以解决了。<br style="padding: 0px; margin: 0px;">代码如下:<br style="padding: 0px; margin: 0px;">协议声明:</p>
<div class="wp_syntax" style="margin-top: 0px; margin-right: 0px; margin-bottom: 1.5em; margin-left: 0px; color: #110000; background-color: #f9f9f9; width: 670px; padding: 0px; border: 1px solid silver;">
<div class="code" style="padding-top: 2px; padding-right: 4px; padding-bottom: 2px; padding-left: 4px; vertical-align: top; margin: 0px;">
<pre class="c">@protocol HTTPRequestDelegate <span style="color: #339933; padding: 0px; margin: 0px;">&lt;</span>NSObject<span style="color: #339933; padding: 0px; margin: 0px;">&gt;</span>
?
@optional
?
<span style="color: #339933; padding: 0px; margin: 0px;">-</span> <span style="color: #009900; padding: 0px; margin: 0px;">(</span><span style="color: #993333; padding: 0px; margin: 0px;">void</span><span style="color: #009900; padding: 0px; margin: 0px;">)</span> requestDidLoadResponse<span style="color: #339933; padding: 0px; margin: 0px;">:</span><span style="color: #009900; padding: 0px; margin: 0px;">(</span>NSString <span style="color: #339933; padding: 0px; margin: 0px;">*</span><span style="color: #009900; padding: 0px; margin: 0px;">)</span>responseDictionary<span style="color: #339933; padding: 0px; margin: 0px;">;</span>
<span style="color: #339933; padding: 0px; margin: 0px;">-</span> <span style="color: #009900; padding: 0px; margin: 0px;">(</span><span style="color: #993333; padding: 0px; margin: 0px;">void</span><span style="color: #009900; padding: 0px; margin: 0px;">)</span> requestDidFailedLoadResourceURLWithError<span style="color: #339933; padding: 0px; margin: 0px;">:</span><span style="color: #009900; padding: 0px; margin: 0px;">(</span>NSError <span style="color: #339933; padding: 0px; margin: 0px;">*</span><span style="color: #009900; padding: 0px; margin: 0px;">)</span>error<span style="color: #339933; padding: 0px; margin: 0px;">;</span>
?
@end</pre>


<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding: 0px;">类声明:</p>
<div class="wp_syntax" style="margin-top: 0px; margin-right: 0px; margin-bottom: 1.5em; margin-left: 0px; color: #110000; background-color: #f9f9f9; width: 670px; padding: 0px; border: 1px solid silver;">
<div class="code" style="padding-top: 2px; padding-right: 4px; padding-bottom: 2px; padding-left: 4px; vertical-align: top; margin: 0px;">
<pre class="c">@interface MyClass <span style="color: #339933; padding: 0px; margin: 0px;">:</span> NSObject <span style="color: #339933; padding: 0px; margin: 0px;">&lt;</span>FooDelegate<span style="color: #339933; padding: 0px; margin: 0px;">,</span>BarDelegate<span style="color: #339933; padding: 0px; margin: 0px;">&gt;</span>
<span style="color: #009900; padding: 0px; margin: 0px;">{</span>
    ...
    <span style="color: #993333; padding: 0px; margin: 0px;">int</span> classIsa<span style="color: #339933; padding: 0px; margin: 0px;">;</span>
    id <span style="color: #339933; padding: 0px; margin: 0px;">&lt;</span>HTTPRequestDelegate<span style="color: #339933; padding: 0px; margin: 0px;">&gt;</span> delegate<span style="color: #339933; padding: 0px; margin: 0px;">;</span>
<span style="color: #009900; padding: 0px; margin: 0px;">}</span>
?
@property <span style="color: #009900; padding: 0px; margin: 0px;">(</span>nonatomic<span style="color: #339933; padding: 0px; margin: 0px;">,</span>assign<span style="color: #009900; padding: 0px; margin: 0px;">)</span> id <span style="color: #339933; padding: 0px; margin: 0px;">&lt;</span>HTTPRequestDelegate<span style="color: #339933; padding: 0px; margin: 0px;">&gt;</span> delegate<span style="color: #339933; padding: 0px; margin: 0px;">;</span>
?
@end</pre>


<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding: 0px;">类实现:</p>
<div class="wp_syntax" style="margin-top: 0px; margin-right: 0px; margin-bottom: 1.5em; margin-left: 0px; color: #110000; background-color: #f9f9f9; width: 670px; padding: 0px; border: 1px solid silver;">
<div class="code" style="padding-top: 2px; padding-right: 4px; padding-bottom: 2px; padding-left: 4px; vertical-align: top; margin: 0px;">
<pre class="c">@implementation MyClass
?
@synthesize delegate<span style="color: #339933; padding: 0px; margin: 0px;">;</span>
?
<span style="color: #339933; padding: 0px; margin: 0px;">-</span> <span style="color: #009900; padding: 0px; margin: 0px;">(</span>id<span style="color: #009900; padding: 0px; margin: 0px;">)</span>initWithDelegate<span style="color: #339933; padding: 0px; margin: 0px;">:</span><span style="color: #009900; padding: 0px; margin: 0px;">(</span>id<span style="color: #009900; padding: 0px; margin: 0px;">)</span>requestDelegate
<span style="color: #009900; padding: 0px; margin: 0px;">{</span>
    self <span style="color: #339933; padding: 0px; margin: 0px;">=</span> <span style="color: #009900; padding: 0px; margin: 0px;">[</span>super init<span style="color: #009900; padding: 0px; margin: 0px;">]</span><span style="color: #339933; padding: 0px; margin: 0px;">;</span>
    <span style="color: #b1b100; padding: 0px; margin: 0px;">if</span> <span style="color: #009900; padding: 0px; margin: 0px;">(</span>self<span style="color: #009900; padding: 0px; margin: 0px;">)</span> <span style="color: #009900; padding: 0px; margin: 0px;">{</span>
        <span style="color: #666666; font-style: italic; padding: 0px; margin: 0px;">//TODO:Send request,etc.</span>
        self.<span style="color: #202020; padding: 0px; margin: 0px;">delegate</span> <span style="color: #339933; padding: 0px; margin: 0px;">=</span> requestDelegate<span style="color: #339933; padding: 0px; margin: 0px;">;</span>
    <span style="color: #009900; padding: 0px; margin: 0px;">}</span>
    <span style="color: #b1b100; padding: 0px; margin: 0px;">return</span> self<span style="color: #339933; padding: 0px; margin: 0px;">;</span>
<span style="color: #009900; padding: 0px; margin: 0px;">}</span>
?
<span style="color: #339933; padding: 0px; margin: 0px;">-</span> <span style="color: #009900; padding: 0px; margin: 0px;">(</span><span style="color: #993333; padding: 0px; margin: 0px;">void</span><span style="color: #009900; padding: 0px; margin: 0px;">)</span>setDelegate<span style="color: #339933; padding: 0px; margin: 0px;">:</span><span style="color: #009900; padding: 0px; margin: 0px;">(</span>id<span style="color: #339933; padding: 0px; margin: 0px;">&lt;</span>HTTPRequestDelegate<span style="color: #339933; padding: 0px; margin: 0px;">&gt;</span><span style="color: #009900; padding: 0px; margin: 0px;">)</span>iDelegate
<span style="color: #009900; padding: 0px; margin: 0px;">{</span>
    delegate <span style="color: #339933; padding: 0px; margin: 0px;">=</span> iDelegate<span style="color: #339933; padding: 0px; margin: 0px;">;</span>
    NSString <span style="color: #339933; padding: 0px; margin: 0px;">*</span>delegateDescription <span style="color: #339933; padding: 0px; margin: 0px;">=</span> <span style="color: #009900; padding: 0px; margin: 0px;">[</span><span style="color: #009900; padding: 0px; margin: 0px;">[</span>iDelegate class<span style="color: #009900; padding: 0px; margin: 0px;">]</span> description<span style="color: #009900; padding: 0px; margin: 0px;">]</span><span style="color: #339933; padding: 0px; margin: 0px;">;</span>
    classIsa <span style="color: #339933; padding: 0px; margin: 0px;">=</span> <span style="color: #009900; padding: 0px; margin: 0px;">(</span><span style="color: #993333; padding: 0px; margin: 0px;">int</span><span style="color: #009900; padding: 0px; margin: 0px;">)</span>objc_getClass<span style="color: #009900; padding: 0px; margin: 0px;">(</span><span style="color: #009900; padding: 0px; margin: 0px;">[</span>delegateDescription UTF8String<span style="color: #009900; padding: 0px; margin: 0px;">]</span><span style="color: #009900; padding: 0px; margin: 0px;">)</span><span style="color: #339933; padding: 0px; margin: 0px;">;</span>
<span style="color: #009900; padding: 0px; margin: 0px;">}</span>
?
<span style="color: #339933; padding: 0px; margin: 0px;">-</span> <span style="color: #009900; padding: 0px; margin: 0px;">(</span><span style="color: #993333; padding: 0px; margin: 0px;">void</span><span style="color: #009900; padding: 0px; margin: 0px;">)</span>callback
<span style="color: #009900; padding: 0px; margin: 0px;">{</span>
    <span style="color: #b1b100; padding: 0px; margin: 0px;">if</span> <span style="color: #009900; padding: 0px; margin: 0px;">(</span><span style="color: #009900; padding: 0px; margin: 0px;">(</span><span style="color: #993333; padding: 0px; margin: 0px;">int</span><span style="color: #009900; padding: 0px; margin: 0px;">)</span>delegate<span style="color: #339933; padding: 0px; margin: 0px;">-&gt;</span>isa <span style="color: #339933; padding: 0px; margin: 0px;">==</span> classIsa<span style="color: #009900; padding: 0px; margin: 0px;">)</span> <span style="color: #009900; padding: 0px; margin: 0px;">{</span>
        <span style="color: #b1b100; padding: 0px; margin: 0px;">if</span> <span style="color: #009900; padding: 0px; margin: 0px;">(</span><span style="color: #009900; padding: 0px; margin: 0px;">[</span>delegate respondsToSelector<span style="color: #339933; padding: 0px; margin: 0px;">:</span>@selector<span style="color: #009900; padding: 0px; margin: 0px;">(</span>requestDidLoadResponse<span style="color: #339933; padding: 0px; margin: 0px;">:</span><span style="color: #009900; padding: 0px; margin: 0px;">)</span><span style="color: #009900; padding: 0px; margin: 0px;">]</span><span style="color: #009900; padding: 0px; margin: 0px;">)</span> <span style="color: #009900; padding: 0px; margin: 0px;">{</span>
                NSString <span style="color: #339933; padding: 0px; margin: 0px;">*</span>responseString <span style="color: #339933; padding: 0px; margin: 0px;">=</span> @<span style="color: #ff0000; padding: 0px; margin: 0px;">"foobar"</span><span style="color: #339933; padding: 0px; margin: 0px;">;</span>
                <span style="color: #009900; padding: 0px; margin: 0px;">[</span>delegate requestDidLoadResponse<span style="color: #339933; padding: 0px; margin: 0px;">:</span>responseString<span style="color: #009900; padding: 0px; margin: 0px;">]</span><span style="color: #339933; padding: 0px; margin: 0px;">;</span>
        <span style="color: #009900; padding: 0px; margin: 0px;">}</span>
    <span style="color: #009900; padding: 0px; margin: 0px;">}</span>
<span style="color: #009900; padding: 0px; margin: 0px;">}</span></pre>


<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding: 0px;">然而由于多线程的原因(发出请求和回调发生是在两个线程上的),会有极少数的情况(测试中发生概率在万分之一以内,和CPU有关)在if ((int)delegate-&gt;isa == classIsa)判断时,delegate当前的isa会和本对象初始化时isa相等,也就是说delegate未被dealloc,而调用回调时,delegate已被dealloc,导致程序crash。避免这种小概率事件的方法是,在delegate中发送请求前[self retain]一下,然后在回调到达时[self release]一下,这样除了避免崩溃以外,还会确保请求已经发送完毕,不会被发送一半。</p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding: 0px;">以上。</p>
<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 10px; margin-left: 0px; padding: 0px;">–OpenThread</p>
<p>?</p>
 
分享到:
评论

相关推荐

    Delegate&Block作回调

    在iOS开发中,回调是一种非常重要的机制,它允许我们在某个操作完成时得到通知或执行相应的代码。本示例主要探讨了两种回调方式:Delegate(代理)和Block(块)。这两种方式各有特点,开发者可以根据实际需求选择...

    delegate与block的使用

    例如,当一个对象需要执行一系列复杂的操作,并且这些操作的回调需要定制化时,Block可以作为Delegate方法的参数来实现。这样既可以利用Delegate的结构化,又可以享受Block的灵活性。 以压缩包中的`MyLayoutSimple`...

    delegate&block

    在iOS和macOS开发中,`delegate`与`block`都是常见的回调机制,用于实现对象间的通信和事件处理。它们各自具有独特的特性和使用场景,理解它们的工作原理和比较是提高编程效率的关键。 首先,我们来看一下`delegate...

    IOS之操作表ActionSheet(免Delegate)

    通常,这里会包含将Blocks转换为Delegate回调的逻辑,当UIActionSheet显示并检测到用户点击时,会调用预先设置的completionBlock。这种方法简化了代码,使得处理UIActionSheet的事件更加直观和简洁。 使用这种...

    Cocoa Touch:UIKit

    UITableView需要配合DataSource(数据源)和Delegate(代理)协议来填充数据和处理用户交互,例如选择某一行时的回调。 `UITextView`则是一个用于输入和显示多行文本的视图。它可以支持用户编辑文本,包括插入、...

    Cocoa基本原理指南

    在Cocoa编程中,Blocks常用于异步操作的回调,如GCD(Grand Central Dispatch)中的任务队列。 7. **Auto Layout**:Auto Layout是iOS和macOS界面布局的一种机制,它可以自动计算和调整UI元素的位置和大小,以适应...

    Block实例------用Block代替delegate来传递值

    Block是Cocoa Touch和Cocoa框架中引入的一种强大的特性,它允许我们将代码块作为一个对象进行传递,这使得代码更加简洁、易读,尤其是在处理异步操作或者回调时。 在Objective-C或Swift中,我们通常使用协议...

    iOS 四种回调方法总结

    Block(块)是Cocoa Touch中引入的一种强大的回调工具,它本质上是一个匿名函数,可以捕获并存储上下文中的变量。Block可以直接嵌入代码中,当特定条件满足时,Block内的代码将被执行。例如,`GCD`(Grand Central ...

    NSHipster Obscure Topics in Cocoa & Objective C.pdf

    3. **Blocks(区块/闭包)**:Objective-C中的Blocks是一种内联函数,可以捕获并存储其定义时的上下文,这使得异步编程、回调和算法表达更为简洁。 4. **GCD (Grand Central Dispatch)**:Apple的多线程解决方案,...

    《cocoa设计模式》源码

    4. **观察者模式** (Observer): NSNotification Center是iOS中的观察者模式实现,允许对象订阅特定的通知并在事件发生时收到回调。这种方式使得对象能响应其他对象的状态变化,而无需强引用。 5. **模型-视图-控制...

    iOS_SDK2.0_API参考手册1

    - delegate:这个属性允许开发者指定一个遵循GizWifiSDKDelegate协议的对象,以便接收和处理SDK的各种事件回调。 - deviceList:这是一个NSArray类型的变量,包含了GizWifiDevice对象,表示当前被SDK发现的设备列表...

    TomCat iOS(iphone)游戏

    在iOS应用中,通常会将资源文件打包在.app bundle中,包括游戏的音效、图片、模型数据等,这些资源在运行时会被加载到内存中供游戏使用。 总结来说,“TomCat”游戏的开发展示了Objective-C在非传统游戏框架下的...

    ios-IOS 代理、通知、block模式.zip

    例如,使用gcd(Grand Central Dispatch)的dispatch_async方法进行异步任务,或者使用UIWebView的loadRequest方法加载网页时设置完成回调。Block模式灵活方便,可读性强,但需要注意的是,如果捕获了强引用循环,...

    iphone面试题秘籍 apple开发必备

    - **原理**:当被观察对象的属性发生改变时,通过`isa`指针的重定向机制,触发观察者的回调。 6. **Notification的理解** - **概念**:基于观察者模式的通知机制,允许一个对象(发布者)向多个对象(观察者)...

    Objective-C面试题.pdf

    - **定义**:Blocks可以作为回调函数传递给方法。 - **使用**:在异步操作完成后执行回调。 10. **多线程的理解与使用**: - **定义**:同时执行多个线程。 - **实现**:使用GCD、NSThread等技术。 #### 五、...

    kkboxiOS开发

    - **Avoid Callback Hell**:过多的嵌套回调会导致代码结构混乱。 #### 五、NotificationCenter - **定义**:用于不同对象之间发送消息的中心,支持观察者模式。 - **实现方式**: - 发布-订阅模式,通过注册和...

    下载压缩包进行解压缩SSZipArchive

    这个库是用Objective-C编写的,因此它很好地兼容了Apple的Cocoa Touch和Cocoa框架,同时也能被Swift项目通过桥接头文件轻松引用。在iOS开发中,SSZipArchive是一个不可或缺的工具,尤其是在处理用户数据备份、资源...

    ocdemo.zip

    Delegate通过遵循特定的Protocol,可以实现对象间的回调和事件响应。 8. KVC与KVO:Key-Value Coding(KVC)和Key-Value Observing(KVO)是OC中用于动态访问和监听对象属性的机制,常用于数据绑定和观察者模式。 ...

    object c 入门教程,非中文版,英文版

    它们常用于异步操作的回调或作为函数参数。 六、Cocoa框架 Cocoa是Apple的开发框架,包括Foundation和AppKit(macOS)或UIKit(iOS)。Foundation提供基本的数据类型和工具,AppKit和UIKit提供图形用户界面的支持...

    block反向传值

    4. **处理回调数据**:在A界面的block中,我们可以接收到B界面传递的数据,并进行相应的处理,更新UI或者其他业务逻辑。 通过这种方式,block反向传值能让我们在不依赖其他机制的情况下高效地完成数据传递。不过,...

Global site tag (gtag.js) - Google Analytics