四.使用关联引用为分类添加数据

  虽然不能在分类中创建实例变量,但是可以创建关联引用(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学习笔记(二)的更多相关文章

  1. WPF的Binding学习笔记(二)

    原文: http://www.cnblogs.com/pasoraku/archive/2012/10/25/2738428.htmlWPF的Binding学习笔记(二) 上次学了点点Binding的 ...

  2. AJax 学习笔记二(onreadystatechange的作用)

    AJax 学习笔记二(onreadystatechange的作用) 当发送一个请求后,客户端无法确定什么时候会完成这个请求,所以需要用事件机制来捕获请求的状态XMLHttpRequest对象提供了on ...

  3. [Firefly引擎][学习笔记二][已完结]卡牌游戏开发模型的设计

    源地址:http://bbs.9miao.com/thread-44603-1-1.html 在此补充一下Socket的验证机制:socket登陆验证.会采用session会话超时的机制做心跳接口验证 ...

  4. JMX学习笔记(二)-Notification

    Notification通知,也可理解为消息,有通知,必然有发送通知的广播,JMX这里采用了一种订阅的方式,类似于观察者模式,注册一个观察者到广播里,当有通知时,广播通过调用观察者,逐一通知. 这里写 ...

  5. java之jvm学习笔记二(类装载器的体系结构)

    java的class只在需要的时候才内转载入内存,并由java虚拟机的执行引擎来执行,而执行引擎从总的来说主要的执行方式分为四种, 第一种,一次性解释代码,也就是当字节码转载到内存后,每次需要都会重新 ...

  6. Java IO学习笔记二

    Java IO学习笔记二 流的概念 在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成. 程序中的输入输 ...

  7. 《SQL必知必会》学习笔记二)

    <SQL必知必会>学习笔记(二) 咱们接着上一篇的内容继续.这一篇主要回顾子查询,联合查询,复制表这三类内容. 上一部分基本上都是简单的Select查询,即从单个数据库表中检索数据的单条语 ...

  8. NumPy学习笔记 二

    NumPy学习笔记 二 <NumPy学习笔记>系列将记录学习NumPy过程中的动手笔记,前期的参考书是<Python数据分析基础教程 NumPy学习指南>第二版.<数学分 ...

  9. Learning ROS for Robotics Programming Second Edition学习笔记(二) indigo tools

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...

  10. Redis学习笔记二 (BitMap算法分析与BitCount语法)

    Redis学习笔记二 一.BitMap是什么 就是通过一个bit位来表示某个元素对应的值或者状态,其中的key就是对应元素本身.我们知道8个bit可以组成一个Byte,所以bitmap本身会极大的节省 ...

随机推荐

  1. POJ 2785 4 Values whose Sum is 0

    4 Values whose Sum is 0 Time Limit: 15000MS   Memory Limit: 228000K Total Submissions: 13069   Accep ...

  2. 在内核中异步请求设备固件firmware的测试代码

    在内核中异步请求设备固件firmware的测试代码 static void ghost_load_firmware_callback(const struct firmware *fw, void * ...

  3. QPaintDevice: Cannot destroy paint device that is being painted

    在paintEvent中,使用QPainter * 绘制图像出现此问题.解决: 1.改为不使用QPainter指针. 2.添上begin(), end() QPainter * painter = n ...

  4. Qt label加边框

    myLabel->setStyleSheet("border:1px solid black"); 简要说明:border就是边缘.px是像素,1px就是边框的宽度.soli ...

  5. 装B必备词汇

    这个页面用来记录遇到的所有高大上的词汇,本词汇集仅限于装B圈交流和讨论. 一致性 hash 算法(consistent hashing) http://blog.csdn.net/sparkliang ...

  6. Maven进价:Maven的安装和目录结构

    一.在windows上安装Maven 1.下载 下载地址:http://maven.apache.org/download.html 下载最新版本 maven3.2.5 2.解压 解压地址:F:\Ja ...

  7. Git 版本管理

    应用情景1:添加文件(单个.多个.目录)到Git版本库,提交一个版本快照. 应用情景2:穿越历史回到过去,版本回退,从当前版本回退到之前提交过的某个版本上. 应用情景3:穿越历史过头了,版本回退多了, ...

  8. redis实现有序的消息队列

    redis是什么东西就不多说了,网上文章一搜一大堆. 首先来说一下我要实现的功能: 类似一个消息中转站吧,如果有人要发送消息,先将消息发到我这里来,然后我这边进行转发,为的就是有一个统一的管理和修改时 ...

  9. yousa_team团队项目 兼职平台 完成展示

    我们团队的团队项目是一个大学生兼职网站,商家可以在网站上发布信息,学生对相应的岗位进行预约,然后根据信誉度来表示用户的信誉,整个平台由管理员监控, 包括修改错误信息,修改用户信誉度,删除过期信息,接受 ...

  10. MySQL安全问题(防范必知)

    对于任何一种数据库来说,安全问题都是非常重要的.如果数据库出现安全漏洞,轻则数据被窃取,重则数据被破坏,这些后果对于一些重要的数据库都是非常严重的.下面来从操作系统和数据库两个层对MySQL的安全问题 ...