类型常量:使用类型常量代替#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. server.xml; lineNumber: 44; columnNumber: 95; 对实体 "characterEncoding" 的引用必须以 ';' 分隔符结尾。

    url="jdbc:mysql://192.169.1.201:3306/raker?useUnicode=true&characterEncoding=UTF-8&zero ...

  2. 理解java注解

    @是java注解,即annotation. 注解功能可以理解为插件,是代码级别的插件,在类的方法上写:@XXX,就是在代码上插入了一个插件. Java注解是附加在代码中的一些元信息,用于一些工具在编译 ...

  3. 入坑第二式 golang入坑系列

    史前必读: 这是入坑系列的第二式,如果错过了第一式,可以去gitbook( https://andy-zhangtao.gitbooks.io/golang/content/ )点个回放,看个重播.因 ...

  4. sublime使用心得

    1.ctrl + shift +p 命令面板 ---> toggle_side_bar 2.ctrl + shift +p 命令面板 --->reindent lines 3.ctrl + ...

  5. microsoft cl.exe 编译器

    cl.exe是visual stdio 内置的编译器,visual stdio包含各种功能,有些功能可能这辈子都用不到,体积庞大,如果是 开发比较大或者有图形的项目,vs是首选.更多情况时更喜欢使用文 ...

  6. Multi-thread & Multi-process

    关于多进程和多线程,教科书上最经典的一句话是“进程是资源分配的最小单位,线程是CPU调度的最小单位”. 对于到底是使用多进程还是多线程, 要根据实际情况来判断,选择更适合的. 具体情况,可以参考下面: ...

  7. EasyMock 常见异常

    1. java.lang.IllegalStateException: calling verify is not allowed in record state 含义:不允许在记录状态(record ...

  8. Python之函数2 嵌套,作用域和闭包(Day12)

    一.函数对象 1.函数是第一类对象,即函数可以当做数据传递 1.1 可以被引用 1.2 可以当做参数传递 1.3 返回值可以是函数 1.4 可以当做容器类型的元素 二.函数的嵌套 1.函数嵌套的调用: ...

  9. Easyui 遮罩实现方式

    项目中在提交Ajax请求时,后台处理数据时间有点长,需要一个遮罩,就随便找了一个实现一下:包含两种方式,个人比较喜欢第二种 第一种: $("#saveMaterial").clic ...

  10. vimium的使用介绍和基本用法

    vimium是chrome浏览器的一个插件,fq去chrome应用商店搜索vimium,下载安装 纯键盘操作,脱离了鼠标,提高效率 核心是f,安装好vimium后只需要按f,输入对应的编号就能进入相应 ...