类型常量:使用类型常量代替#define

1. 普通常量

//.m
#import "xxxxx.h"
static const NSTimerInterval kAnimationDuration = 0.3; //放在.m文件的#import之后即可,常量名称以k开头。
@implemenation xxxxx
@end

2. 公开常量

//注意不同类型的写法,最好以类名作为前缀。
//xxxxx.h
extern NSString *const xxxxxStringConstant;
extern const NSTimerInterval xxxxxAnimationDuration; //xxxxx.m
NSString *const xxxxxStringConstant = @"VALUE";
const NSTimerInterval xxxxxAnimationDuration = 0.3;

枚举类型的声明:用NS_ENUM代替普通枚举,用NS_OPTIONS代替定义选项的枚举

1. NS_ENUM极其传统写法

//声明一个EOCConnectionState枚举
typedef NS_ENUM(NSUInteger, EOCConnectionState) {
EOCConnectionStateDisconnected,
EOCConnectionStateConnecting,
EOCConnectionStateConnected,
}; //传统写法:
enum EOCConnectionState : NSUInteger {
EOCConnectionStateDisconnected,
EOCConnectionStateConnecting,
EOCConnectionStateConnected,
};
typedef enum EOCConnectionState EOCConnectionState;

2. NS_OPTIONS极其传统写法

//声明一个EOCPermittedDirection选项枚举
typedef NS_OPTIONS(NSUInteger, EOCPermittedDirection) {
EOCPermittedDirectionUp,
EOCPermittedDirectionDown,
EOCPermittedDirectionLeft,
EOCPermittedDirectionRight,
}; //传统写法:
enum EOCPermittedDirection: NSUInteger {
EOCPermittedDirectionUp = << ,
EOCPermittedDirectionDown = << ,
EOCPermittedDirectionLeft = << ,
EOCPermittedDirectionRight = << ,
};
typedef enum EOCPermittedDirection EOCPermittedDirection;

属性特质:原子性、读写权限、内存管理语义、方法名

1. 原子性:
atomic或者不写,表示使用同步锁;
nonatomic,表示不使用同步锁。

在iOS开发中同步锁会非常影响性能,所以包括SDK在内一般都使用nonatiomic,也就是说iOS系统中的属性通常不是线程安全的。
在OSX中不存在性能问题。

2. 读写权限:
readwrite,同时拥有getter和setter方法;
readonly,只有getter方法。

该属性由@synthesize实现,编译器才会自动生成相应的getter、setter。新版本不再需要指定@synthesize了。

3. 内存管理语义:
assign,对简单类型的赋值操作。
strong,强类型。
weak,弱类型。
unsafe_unretained,与weak类似,不同的是,当对象被销毁时,属性值不会自动被清空。
copy,与strong类似,不同的是,设置方法不会保留新值,而是将其拷贝。

由于NSString*的新值可能被指定为NSMutableString的实例,为防止此属性值被修改,使用copy特质。
延伸:新值可能为mutable的对象的,都应该copy。

//若声明copy特质的属性
@property (copy) NSString *title; //在实现自定义的初始化方法时,也要遵从copy
_title = [aNSString copy]; /* 注意:其他的特质也是同样道理。 */

4. 方法名:
getter=<name>,指定getter方法名,如果属性是Boolean型,可以指定is前缀,如: @property (noatomic, getter=isOn) BOOL on; 
setter=<name>,指定setter方法名,不常用。

实现description方法:NSObject返回“<类名, 指针>”格式字符串,重写它,方便NSLog和(lldb)调试。

1. description方法

- (NSString *)description
{
return [NSString stringWithFormat:@"<%@: %p, \"%@ %@\">", [self class],self,_firstName,_lastName];
}

2. debugDescription方法:如果不重写,就是简单调用description方法。这个方法在(lldb)调试的时候,用po命令打印输出,如:po person

-(NSString *)debugDescription {
return [NSString stringWithFormat:@"<%@: %p, %@>",
[self class],
self,
@{@"firstName":_firstName,
@"lastName":_lastName,
}];
}

多个属性可以使用NSDictionary的description方法,如上面这个实现。

输出窗口:

(lldb) po person
<XXXPerson: 0x7fd871f00080, {
firstName = Bob;
lastName = Wei;
}> 2015-06-08 17:32:41.094 test-coredata[4774:269533] person = <XXXPerson: 0x7fd871f00080, "Bob Wei">

实现NSCopying协议:重写copyWithZone方法。

//.h
#import <Foundation/Foundation.h> @interface XXXPerson : NSObject <NSCopying>
@property (nonatomic, copy, readonly) NSString *firstName;
@property (nonatomic, copy, readonly) NSString *lastName;
- (instancetype)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName;
- (void)addFriend:(XXXPerson *)person;
- (void)removeFriend:(XXXPerson *)person;
@end //.m
#import "XXXPerson.h" @implementation XXXPerson {
NSMutableSet *_friends;
} - (void)addFriend:(XXXPerson *)person {
[_friends addObject:person];
} - (void)removeFriend:(XXXPerson *)person {
[_friends removeObject:person];
} - (id)copyWithZone:(NSZone *)zone {
XXXPerson *copy = [[[self class] allocWithZone:zone] initWithFirstName:_firstName lastName:_lastName];
copy->_friends = [_friends mutableCopy];
return copy;
} @end

如果实现NSMutableCopying协议:重写mutableCopyWithZone方法,并且应该总是返回可变对象(mutableCopy方法),而重写的copyWithZone总应该返回不变对象(copy方法)。

以上代码实现了一个浅拷贝,如果需要实现深拷贝,代码如下:

- (id)deepCopy {
XXXPerson *copy = [[[self class] alloc] initWithFirstName:_firstName lastName:_lastName];
copy->_friends = [[NSMutableSet alloc] initWithSet:_friends copyItems:YES];
return copy;
}

NSMutableSet的initWithSet:方法中,copyItems为YES时,会复制每一项,即实现了NSSet集合的深拷贝。

委托和数据协议:用一个结构体来防止[delegate respondsToSelector:]方法被反复调用。

//.h
#import <Foundation/Foundation.h> @class XXXNetworkFetcher; @protocol XXXNetworkFetcherDelegate <NSObject> @optional
- (void)networkFetcher:(XXXNetworkFetcher *)fetcher didReceiveData:(NSData *)data;
- (void)networkFetcher:(XXXNetworkFetcher *)fetcher didFailWithError:(NSError *)error;
- (void)networkFetcher:(XXXNetworkFetcher *)fetcher didUpdateProgressTo:(float)progress; @end @interface XXXNetworkFetcher : NSObject @property (weak, nonatomic) id<XXXNetworkFetcherDelegate> delegate; @end //.m
#import "XXXNetworkFetcher.h" @interface XXXNetworkFetcher() {
//C语言特性:“位段”(bitfield)数据类型,右边数字1表示只占用一个二进制位
struct {
unsigned int didReceiveData :;
unsigned int didFailWithError :;
unsigned int didUpdateProgressTo :;
} _delegateFlags;
} @end @implementation XXXNetworkFetcher - (void)setDelegate:(id<XXXNetworkFetcherDelegate>)delegate {
_delegate = delegate;
_delegateFlags.didReceiveData = [delegate respondsToSelector:@selector(networkFetcher:didReceiveData:)];
_delegateFlags.didFailWithError = [delegate respondsToSelector:@selector(networkFetcher:didFailWithError:)];
_delegateFlags.didUpdateProgressTo = [delegate respondsToSelector:@selector(networkFetcher:didUpdateProgressTo:)];
} - (void)foo {
NSData *data = [[NSData alloc] init];
if (_delegateFlags.didReceiveData) {
[_delegate networkFetcher:self didReceiveData:data];
}
} @end

块block:栈块、堆块和全局块。

定义块的时候会被分配到栈中,它只在定义范围内有效。如果在if..else语句中定义块(栈块),有可能导致块呗编译器复写掉。加入copy方法后会将块拷贝到堆中(堆块),就避免了上述可能发生的错误:

- (void)foo {
void(^block)();
_switch = !_switch;
if (_switch) {
block = [^{
NSLog(@"Block A");
} copy];
} else {
block = [^{
NSLog(@"Block B");
} copy];
}
block();
}

如果块是直接定义的,没有捕获任何外围变量,那么它的全部信息能在编译器确定,(区别于栈块、堆块)称作全局块。

-

Effective Objective-C手记的更多相关文章

  1. 【iOS】关联属性存取数据

    有时候我们需要在现有的类存放一些额外的信息,通常的做法是继承一个子类,然后定义新增加的属性,然而如果我们为每个需要的类都添加一个类显得太麻烦了,objc提供了一个关联属性的特性,可以给一个对象关联一个 ...

  2. iOS 学习资源

    这份学习资料是为 iOS 初学者所准备的, 旨在帮助 iOS 初学者们快速找到适合自己的学习资料, 节省他们搜索资料的时间, 使他们更好的规划好自己的 iOS 学习路线, 更快的入门, 更准确的定位的 ...

  3. Automake

    Automake是用来根据Makefile.am生成Makefile.in的工具 标准Makefile目标 'make all' Build programs, libraries, document ...

  4. iOS学习资料整理

    视频教程(英文) 视频 简介 Developing iOS 7 Apps for iPhone and iPad 斯坦福开放教程之一, 课程主要讲解了一些 iOS 开发工具和 API 以及 iOS S ...

  5. iOS 学习

    iOS 学习资料 (适合初学者) 本文资料来源于GitHub 一.视频教程(英文) Developing iOS 7 Apps for iPhone and iPad斯坦福开放教程之一, 课程主要讲解 ...

  6. iOS 学习资料汇总

    (适合初学者入门) 本文资料来源于GitHub 一.视频教程(英文) Developing iOS 7 Apps for iPhone and iPad斯坦福开放教程之一, 课程主要讲解了一些 iOS ...

  7. ios书籍推荐

    1.Objective-C Programming  内容不多, 却都是精华, 有了一点 C 语言基础可以快速阅读此书, 大概一天时间就可以看完, 看完后对 iOS 开发能够有个基本的印象. 2.iO ...

  8. iOS Learning

    转载自:http://www.cocoachina.com/ios/20150111/10894.html iOS 学习资料整理 2015-01-11 20:20 编辑: suiling 分类:iOS ...

  9. BlocksKit的使用

    一.引言 众所周知Block已被广泛用于iOS编程.它们通常被用作可并发执行的逻辑单元的封装,或者作为事件触发的回调.Block比传统回调函数有2点优势: 允许在调用点上下文书写执行逻辑,不用分离函数 ...

随机推荐

  1. window 注册表上下文菜单如何配置?

    注册表结构? Keys Abbreviation Description 描述 HKEY_CLASSES_ROOT HKCR Stores file association and COM objec ...

  2. HDU 4193 Non-negative Partial Sums(单调队列)

     题目大意: 给定一个长度为n的循环序列.从n个不同位置開始,问有几个位置使得一下情况成立:全部前缀的和都大等于0(n <=1000000). 下午的训练赛.之前没学过单调队列所以用的线段树 ...

  3. InnoDB的三个关键特性

    一.插入缓冲(insert buffer) 对于非聚集索引的插入和更新,不是每一次直接插入索引页中,而是首先判断插入的非聚集索引页是否在缓冲池中,如果在,则直接插入,否则, 先放入一个插入缓冲区中.好 ...

  4. 004-诠释 Java 工程师【二】

    三.框架篇 框架基础 反射:反射是Java开发的一类动态相关机制.因为本身Java语言并不是一款动态语言,如果我们想要得到程序动态的效果,因此便引入了反射机制这一概念. 怎么表达反射? 能用反射做什么 ...

  5. 017-Hadoop Hive sql语法详解7-去重排序、数据倾斜

    一.数据去重排序 1.1.去重 distinct与group by 尽量避免使用distinct进行排重,特别是大表操作,用group by代替 -- 不建议 select DISTINCT key ...

  6. mysql终结篇

    一.mysql中not null unique和primary key 的区别 1.not null unique 是给一个字段设置非空且唯一的特性,当表中字段没有设置primary key的主键特性 ...

  7. mysql数据库中表记录的玩法

    一.增加表记录(相当于插入表记录) 1. 插入完整数据(顺序插入) 语法一: INSERT INTO 表名(字段1,字段2,字段3…字段n) VALUES(值1,值2,值3…值n); 语法二: INS ...

  8. Ubuntu安装配置samba

    一. samba的安装: sudo apt-get insall sambasudo apt-get install smbfs 二. 创建共享目录: mkdir /home/chars/shares ...

  9. 利用FFmpeg将RTSP转码成RTMP发布在RED5

    安装jdk,并设置环境  from:http://www.w3c.com.cn/%E5%88%A9%E7%94%A8ffmpeg%E5%B0%86-ipcamera-%E7%9A%84rtsp%E8% ...

  10. CRC冗余校验码的介绍和实现

    from:http://yoyo.play175.com/p/200.html 节选至百度百科: 首先,任何一个由二进制数位串组成的代码,都可以惟一地与一个只含有0和1两个系数的多项式建立一一对应的关 ...