`

ios delegate你必须知道的事情

阅读更多
ios delegate你必须知道的事情

转:http://popcornylu.blogspot.com/2011/07/delegate.html

当你开始写iOS程式不久,应该开始面对到很多的delegate,
不管是用别人的library或是自己写library,可能都逃不了delegate。
为了怕有些人不知道什么是delegate,在这边简单的介绍一下,
delegate中文叫做委托,通常会用在class内部把一些事件处理"委托"给别人去完成。
举个例子,XML Parser可能他知道怎么parse xml,但是parse到的东西要怎么处理xml parser可能不知道。
所以NSXMLParser就提供了一个NSXMLParserDelegate给client去实作,
当parse到某个element的时候,就callback delegate所定义的message,
让他client自己去决定怎么去处理这个element。
好吧,我承认我解释的很模糊,不过我这篇本来就不是要你搞懂什么是delegate,
而是针对使用或是设计delegate的时候,可能会要注意的事情。

在我们的class中设计delegate的时候,我们通常会有几个注意事项。
假设我的class叫做MyClass,那我们可能会有定义一个MyClassDelegate这个protocol当作我的delegate protocol。
而MyClass中我们可能是这样写。
@protocol MyClassDelegate <NSObject>
- (void) myClassOnSomeEvent:(MyClass*)myClass;
@end

@interface MyClass
{
    id<MyClassDelegate> _delegate;
}
@property (nonatomic, assign) delegate;
@end
上面的code我们注意到delegate此property是定义为@property (assign)。
为什么我们不用retain而要用assign呢?
原因就是在于iOS的reference counting的环境中,我们必须解决circular count的问题。
让我们来写写我们平常都怎么用delegate的,下面的code我想大家应该不陌生
- (void)someAction
{
   myClass = [MyClass new];
   myClass.delegate = self;
   ....
}
这边很快的就出现circular reference了
假设上面的code是写在一个myViewController的物件当中,
之后一旦myViewController的reference count变成1的时候,
myViewController跟myClass这两个兄弟两只剩下互相retain,那就变成了孤岛,也​​就因此造成了memory leak!!!


也因为这样,iOS官方文件才会要建议我们所以的delegate都要用assign property。
也就是所谓"weak reference"的property,他的特色就是虽然会持有对方的reference,但是不会增加retain count。
如此下来,当myViewController的retain count变成0,则会dealloc。
同时在dealloc中,也一并把myClass release,则myClass也跟着被release。
- (void)dealloc
{
   [myClass release];
   [super dealloc];
}



事情就结束了吗? 还没有唷...
这边还有一个大家常常忘记的重点,那就是上面的dealloc这样写会有潜在危险。
应该要改成这样
- (void)dealloc
{
   myClass.delegate = nil;
   [myClass release];
   [super dealloc];
}
你可能会很纳闷,myClass不是马上就会被release了吗? 干嘛要先把他的delegate设成nil?
那是因为我们假设myClass会马上会被dealloc,但是现实状况这个是不一定的,
有可能里面内部有建个NSURLConnection,或是正在做某件事情而让其他物件也retain myClass。
如果myClass没有马上dealloc,那他的myClass.delegate不就正指向一个不合法的位置了吗? (此种pointer称作dangling pointer)



解决方法是在MyViewController的dealloc中,在release myClass之前,
要先把原本指向自己的delegate改设成nil,这样才可以避免crash发生。
在我之前写的project,很大一部份的crash都是这样造成的,因为这个问题通常不是每次都发生,
但是发生的时候确很难在重新复制,所以不可不慎啊。



但是很兴奋的是到了iOS5中的Automatic Reference Counting 这个问题可以有所改善。
在ARC中提出了一个新的weak reference的概念来取代原本的assign,
weak reference指到的物件若是已经因retain count归零而dealloc了,则此weak reference也自动设成nil。
而原本​​旧的这种assign的作法,在ARC中叫做__unsafe_unretained,这只是为了相容iOS4以下的版本。

回顾重点:
如果你是写library给别人用的,记得把你的delegate设成assign property,这样才不会造成circular reference
当你是要始用别人的library,记得在你自己dealloc的时候,把delegate设成nil,以避免crash的事情发生。

References
[1]Communicating with Objects
  • 大小: 23.9 KB
  • 大小: 31.2 KB
  • 大小: 39.5 KB
  • 大小: 39.6 KB
0
3
分享到:
评论
1 楼 mikixiyou 2013-03-28  
此文写的很好!
不知道博主有没有遇到这样的问题?delegate的方法没有被调用。
如您描述的环境,myViewController被另一个viewcontroller调用。简单的调用过程如下:
myViewController *xx=[myViewController alloc] init];
[xx yyy];
然后,myViewController中的delegate中的方法却没有调用。

相关推荐

    delegate和block的使用

    在iOS和macOS开发中,`delegate`和`block`是两种常见的对象间通信机制,它们各自具有不同的特性和用途。了解并熟练掌握这两种技术对于编写高效、灵活的代码至关重要。 ## delegate(代理) `delegate`是Objective-...

    iOS Programming The Big Nerd Ranch Guide 6th Edition

    - **代理方法(Delegate Methods)**:控制表视图的行为,如选择行时发生的事情。 - **编辑模式(Edit Mode)**:允许用户添加或删除表视图中的行。 通过本节的学习,读者将能够熟练地创建自己的表视图,填充数据,...

    IOS 中UIKit-UIPageControl利用delegate定位圆点位置

    IOS 中UIKit-UIPageControl利用delegate定位圆点位置 在UIScrollView中会添加UIPageControl作为页码标识,可以让用户清楚的知道当前的页数。我们需要优化的一点是让pageControl的小圆点精确的跟着scrollView而定位...

    ios常用动画封装类

    * 动画的代理,如果你想在动画开始和结束的时候做一些事,可以设置此属性,它会自动回调两个代理方法. * * @see CAAnimationDelegate (按下command键点击) */ animation.delegate = self; /** duration * *...

    ios-cell上添加运行时按钮.zip

    在iOS开发中,我们经常需要在UITableView的Cell中动态地添加和配置控件,比如UIButton。这个"ios-cell上添加运行时按钮.zip"文件显然涉及到了如何在Cell中利用运行时(Runtime)来实现特定功能,特别是针对点击事件...

    ios应用源码之委托代理 2018127

    在iOS应用开发中,委托代理(Delegate)是一种重要的设计模式,它使得对象间可以进行通信,特别是当一个对象需要依赖另一个对象的行为时。这个模式在iOS SDK中被广泛使用,尤其是在用户界面(如UITableView,...

    毕业设计电商网站源码-iOS:iOS开发者Swift/Objective-C技能

    ReactiveCocoa为事件提供了很多处理方法,而且利用RAC处理事件很方便,可以把要处理的事情,和监听的事情的代码放在一起,这样非常方便我们管理,就不需要跳到对应的方法里。非常符合我们开发中高聚合,低耦合的思想...

    iOS ScrollView嵌套tableView联动滚动的思路与最佳实践

    iOS 开发中,_scrollView 嵌套 tableView 联动滚动是一个常见的交互方式,但它也存在一些问题,如滚动手势的冲突、页面的多层级嵌套等。下面我们将讨论 iOS ScrollView 嵌套 tableView 联动滚动的思路与最佳实践。 ...

    ios-app-rentcar:SwiftUI项目

    在“ios-app-rentcar-master”这个文件夹中,你可能找到以下文件和目录: 1. `ContentView.swift`: 应用的主视图。 2. `Models`: 存放车辆模型数据的目录。 3. `Views`: 包含各种自定义视图的文件。 4. `Resources`...

    iPhone源码分析(委托模式)

    ModalViewController中的`delegate`属性是一个遵循`ModalViewControllerDelegate`协议的对象,这个协议定义了一些方法,使得ModalViewController可以通知它的代理(在这里是MainViewController)一些特定事件的发生...

    代理、block传值

    在iOS和macOS开发中,代理(Delegate)和代码块(Block)是两种常见的对象间通信...项目中的`1116_04 delegate and block.xcodeproj`可能包含了一些示例代码,你可以通过运行和研究这些代码来加深对代理和Block的理解。

    藏经阁-小红书移动端自动化数据采集实践.pdf

    Referrer & Parent简单的说就是你从哪来,和你是谁生的问题。 自动采集页面数据 页面数据如何自动采集?页面数据其实就是记录每个页面的生命周期。在iOS中就是ViewController的生命周期,在Android中就是Activity/...

    ETBluetoothPrinterManager:iOS中用于连接蓝牙设备的库。使用非常简单!!!

    ET蓝牙打印机管理器 ...通过这些委托方法,您可以做一些事情。 - (void)bluetoothStatusHasChange:(BOOL)isOn; - (void)didDiscoverPeripherals:(NSArray *)peripherals; - (void)didConnectPeripheral;

    swift-一个优雅的方式向用户显示正在发生的事情并准备他正在等待的内容

    "swift-一个优雅的方式向用户显示正在发生的事情并准备他正在等待的内容"这一主题,主要探讨的是如何通过进度条视图(Progress Bar View)来实现这一目标。进度条视图是一种用户界面元素,它能展示任务的进度,让...

    JS与Native交互

    作者FarWinter,源码IOS-JsAndNativeDemo,通过webview代理方法 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)...

    代理传值 简单实现

    代理模式是Objective-C和Swift中常见的一种设计模式,用于对象间的通信,特别是当一个对象需要通知另一个对象它发生了某些事情时。 首先,我们需要理解UITextField和UILabel的基本概念。UITextField是iOS中的文本...

    BasicUserNotification.m

    //所以往第一个界面上添加一个label,看标签是否会显示一些内容 UILabel *label = [[UILabel alloc]init]; label.frame = CGRectMake(0, 250, 300, 200); label.numberOfLines = 0; label.textColor = [UIColor...

Global site tag (gtag.js) - Google Analytics