IOS6学习笔记(二)
四.使用关联引用为分类添加数据
虽然不能在分类中创建实例变量,但是可以创建关联引用(associative reference)。通过关联引用,你可以向任何对象中添加键-值(key-value)数据。
假如有一个Person类,这个person类可能会被用在其他程序中,有些电子邮件地址(emailAddress)这个字段是有意义的,有些时候这个字段是没有用的。一个比较好的解决方案就是使用分类为Person类添加一个名为emailAddress的属性,这样可以避免不需要emailAddress时的开销。或许Person类并不是你写的,改类的维护者也不会为你添加这个属性。这种情况下,要怎么解决问题看?首先看一下Person类的定义:
@interface Person:NSObject
@property (nonatomic, readwrite, copy) NSString *name;
@end;
@implementation Person
@end
现在使用关联引用在分类中添加一个emailAddress属性:
#import<objc/runtime.h>
@interface Person(EmailAddress)
@property (nonatomic, readwrite, copy) NSString *emailAddress;
@end
@implementation Person (EmailAddress)
static char emailAddressKey;
- (NSString *)emailAddress{
return objc_getAssociatedObject(self, &emailAddressKey);
}
- (void)setEmailAddress:(NSString *)emailAddress{
objc_setAssociatedObject(self, &emailAddressKey,emailAddress,OBJC_ASSOCIATION_COPY);
}
@end
可以看出,关联引用是基于键(key)的内存地址的,而不是键的值。在emailAddressKey中储存的内容并不重要,但是它需要一个唯一地址,所以通常使用一个未赋值的static char 作为键。
如果要在警告面板中关联一个对象,使用关联引用是一个非常好的方式。例:
#import "ViewController.h"
#import <objc/runtime.h>
@implementation ViewController
static const char kRepresentedObject;
- (IBAction)doSomething:(id)sender {
UIAlertView *alert = [[UIAlertViewalloc]
initWithTitle:@"Alert" message:nil
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
objc_setAssociatedObject(alert, &kRepresentedObject,
sender,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[alert show];
}
- (void)alertView:(UIAlertView *)alertView
clickedButtonAtIndex:(NSInteger)buttonIndex {
UIButton *sender = objc_getAssociatedObject(alertView,
&kRepresentedObject);
self.buttonLabel.text = [[sender titleLabel] text];
}
@end
五.类扩展(class extension)
类扩展的声明方式跟分类很像,只不过括号内的名字是空的:
@interface MyObject()
- (void)doSomething;
@end
类扩展是在.m文件中声明私有方法的一个很棒的方式。不同于分类,在类扩展中声明的方法与在类中声明的方法是完全一致的,这些方法必须全部实现(分类的方法不必全都实现),且在编译时被添加到类中,而分类是在运行时添加。在类扩展中也可以声明合成属性。
六.协议
协议跟类一样可以继承。协议应该总是继承<NSObject>,就像类总是继承NSObject一样。委托协议(delegate protocol)的第一个参数总是委托对象。正是因此,一个委托才能管理多个委托对象。比如,一个控制器就可以作为多个UIAlertView实例的委托来使用。注意在委托对象之外是否还有其他参数,这对命名约定有一定影响。如果没有参数,类名应该最后出现(numberOfSectionsInTableView:);如果有其他参数,类名要首先出现,作为它自身的参数(tableView:numberOfRowsInSection:)。
创建协议之后,通常还需要一个属性以便于操作它,通常使用id<Protocol>的方式来声明:
@property(nonatomic, readwrite, weak) id<MyDelegate> delegate;
这表示“与MyDelegate协议相容的任何对象”。同事使用类和协议声明一个属性也是可以的,而且可以使用多个协议:
@property(nonatomic, readwrite, weak) MyClass *<MyDelegate,UITableViewDelegate> delegate;
这个属性声明是说delegate必须是MyClass或其子类的对象,而且必须同时与<MyDelegate>和<UITableViewDelegate>协议相容。
六.单例
建议使用Grand Center Dispatch(CCD):
+ (MYSingleton *)sharedSingleton{
static dispatch_once_t pred;
static MYSingleton *instance = nil;
dispatch_once(&pred, ^{instance = [[self alloc] init];});
return instance;
}
这样编写方便、快速,而且线程安全。其他方法要在+sharedSingleton中添加一个@synchronize以达到线程安全的目的,但是这种做法在每次调用+sharedSingleton时都会导致性能显著下降。另外,还可以使用+initialize,但使用GCD的方法最简单。
强制执行单例:
+ (MYSingleton *)sharedSingleton{
static dispatch_once_t pred;
static MYSingleton *instance = nil;
dispatch_once(&pred, ^{instance = [[self alloc] init];});
return instance;
}
- (id)init{
//禁用调用-init或new
NSAssert(NO, @"Cannot create instance of Singleton");
//在这里,你可以返回nil或[self initSingleton],由你来决定是返回nil还是返回[self...]
return nil;
}
//真正的(私有)init方法
- (id)initSingleton{
self = [super init];
if(self){
//初始化代码
}
return self;
}
IOS6学习笔记(二)的更多相关文章
- WPF的Binding学习笔记(二)
原文: http://www.cnblogs.com/pasoraku/archive/2012/10/25/2738428.htmlWPF的Binding学习笔记(二) 上次学了点点Binding的 ...
- AJax 学习笔记二(onreadystatechange的作用)
AJax 学习笔记二(onreadystatechange的作用) 当发送一个请求后,客户端无法确定什么时候会完成这个请求,所以需要用事件机制来捕获请求的状态XMLHttpRequest对象提供了on ...
- [Firefly引擎][学习笔记二][已完结]卡牌游戏开发模型的设计
源地址:http://bbs.9miao.com/thread-44603-1-1.html 在此补充一下Socket的验证机制:socket登陆验证.会采用session会话超时的机制做心跳接口验证 ...
- JMX学习笔记(二)-Notification
Notification通知,也可理解为消息,有通知,必然有发送通知的广播,JMX这里采用了一种订阅的方式,类似于观察者模式,注册一个观察者到广播里,当有通知时,广播通过调用观察者,逐一通知. 这里写 ...
- java之jvm学习笔记二(类装载器的体系结构)
java的class只在需要的时候才内转载入内存,并由java虚拟机的执行引擎来执行,而执行引擎从总的来说主要的执行方式分为四种, 第一种,一次性解释代码,也就是当字节码转载到内存后,每次需要都会重新 ...
- Java IO学习笔记二
Java IO学习笔记二 流的概念 在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成. 程序中的输入输 ...
- 《SQL必知必会》学习笔记二)
<SQL必知必会>学习笔记(二) 咱们接着上一篇的内容继续.这一篇主要回顾子查询,联合查询,复制表这三类内容. 上一部分基本上都是简单的Select查询,即从单个数据库表中检索数据的单条语 ...
- NumPy学习笔记 二
NumPy学习笔记 二 <NumPy学习笔记>系列将记录学习NumPy过程中的动手笔记,前期的参考书是<Python数据分析基础教程 NumPy学习指南>第二版.<数学分 ...
- Learning ROS for Robotics Programming Second Edition学习笔记(二) indigo tools
中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...
- Redis学习笔记二 (BitMap算法分析与BitCount语法)
Redis学习笔记二 一.BitMap是什么 就是通过一个bit位来表示某个元素对应的值或者状态,其中的key就是对应元素本身.我们知道8个bit可以组成一个Byte,所以bitmap本身会极大的节省 ...
随机推荐
- Java8简明教程(转载)
ImportNew注:有兴趣第一时间学习Java 8的Java开发者,欢迎围观<征集参与Java 8原创系列文章作者>. 以下是<Java 8简明教程>的正文. “Java并没 ...
- UITableViewCell分割线左边部分缺少一些的解决方法
-(void)viewDidLayoutSubviews { if ([self.mytableview respondsToSelector:@selector(setSeparato ...
- MAC 入门
1.安装java jdk eclipse 后发现运行不了,原因是JAVA_HOME 没有设置,真操蛋 export JAVA_HOME=`/usr/libexec/java_home` 2.安装bre ...
- ios auto layout demystified (一)
Ambiguous Layout 在开发过程中,你可以通过调用hasAmbiguousLayout 来测试你的view约束是否足够的.这个会返回boolean值.如果有一个不同的frame就会返回ye ...
- AVL树(二)之 C++的实现
概要 上一章通过C语言实现了AVL树,本章将介绍AVL树的C++版本,算法与C语言版本的一样. 目录 1. AVL树的介绍2. AVL树的C++实现3. AVL树的C++测试程序 转载请注明出处:ht ...
- Hadoop入门进阶课程8--Hive介绍和安装部署
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,博主为石山园,博客地址为 http://www.cnblogs.com/shishanyuan ...
- Windows7 x64 系统下安装 Nodejs 并在 WebStorm 9.0.1 下搭建编译 LESS 环境
1. 打开Nodejs官网http://www.nodejs.org/,点“DOWNLOADS”,点64-bit下载“node-v0.10.33-x64.msi”. 2. 下载好后,双击“node-v ...
- [pyhton]python内建方法
撸一遍python的内建方法 这样做的好处就是:我如果要完成一个功能的时候,如果能用内建方法完成,就用内建方法.这样可以提高效率,同时使自己的代码更加优雅.哎呦?那岂不是撸完就是python高手了?我 ...
- JS数组追加数组采用push.apply的坑
JS数组追加数组没有现成的函数,这么多年我已经习惯了a.push.apply(a, b);这种自以为很酷的,不需要写for循环的写法,一直也没遇到什么问题,直到今天我要append的b是个很大的数组时 ...
- 《构建之法》之第8、9、10章读后感 ,以及sprint总结
第8章: 主要介绍了软件需求的类型.利益相关者,获取用户需求分析的常用方法与步骤.竞争性需求分析的框架NABCD,四象限方法以及项目计划和估计的技术. 1.软件需求:人们为了解决现实社会和生活中的各种 ...