Effective Objective-C手记
类型常量:使用类型常量代替#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手记的更多相关文章
- 【iOS】关联属性存取数据
有时候我们需要在现有的类存放一些额外的信息,通常的做法是继承一个子类,然后定义新增加的属性,然而如果我们为每个需要的类都添加一个类显得太麻烦了,objc提供了一个关联属性的特性,可以给一个对象关联一个 ...
- iOS 学习资源
这份学习资料是为 iOS 初学者所准备的, 旨在帮助 iOS 初学者们快速找到适合自己的学习资料, 节省他们搜索资料的时间, 使他们更好的规划好自己的 iOS 学习路线, 更快的入门, 更准确的定位的 ...
- Automake
Automake是用来根据Makefile.am生成Makefile.in的工具 标准Makefile目标 'make all' Build programs, libraries, document ...
- iOS学习资料整理
视频教程(英文) 视频 简介 Developing iOS 7 Apps for iPhone and iPad 斯坦福开放教程之一, 课程主要讲解了一些 iOS 开发工具和 API 以及 iOS S ...
- iOS 学习
iOS 学习资料 (适合初学者) 本文资料来源于GitHub 一.视频教程(英文) Developing iOS 7 Apps for iPhone and iPad斯坦福开放教程之一, 课程主要讲解 ...
- iOS 学习资料汇总
(适合初学者入门) 本文资料来源于GitHub 一.视频教程(英文) Developing iOS 7 Apps for iPhone and iPad斯坦福开放教程之一, 课程主要讲解了一些 iOS ...
- ios书籍推荐
1.Objective-C Programming 内容不多, 却都是精华, 有了一点 C 语言基础可以快速阅读此书, 大概一天时间就可以看完, 看完后对 iOS 开发能够有个基本的印象. 2.iO ...
- iOS Learning
转载自:http://www.cocoachina.com/ios/20150111/10894.html iOS 学习资料整理 2015-01-11 20:20 编辑: suiling 分类:iOS ...
- BlocksKit的使用
一.引言 众所周知Block已被广泛用于iOS编程.它们通常被用作可并发执行的逻辑单元的封装,或者作为事件触发的回调.Block比传统回调函数有2点优势: 允许在调用点上下文书写执行逻辑,不用分离函数 ...
随机推荐
- Wireshark网络分析工具(一)
关于Wireshark,熟悉网络或网络性能方面的同学应该知道,使用Wireshark工具通过抓取数据包,对系统网络问题进行分析,该工具简单.易用.易学! 百度百科上面是这样描述的:Wireshark( ...
- MySQL 中有关auto_increment及auto_increment_offset方面的介绍
数据库查询中,涉及到auto_increment中的参数变量一共有两个 [root@localhost][(none)]> show variables like 'auto_inc%'; +- ...
- 人工智能-baidu-aip语音合成(文字转语音)
from aip import AipSpeech APP_ID = ' APP_KEY = 'DhXGtWHYMujMVZZGRI3a7rzb' SECRET_KEY = 'PbyUvTL31fIm ...
- linux 安装zip/unzip/g++/gdb/vi/vim等软件
近期公司新配置了一台64位云server.去部署的时候发现,没有安装zip/unzip压缩解压软件. 于是仅仅好自己安装这两个软件.linux最好用的还是yum. 两个指令就安装好了. 首先把软件安装 ...
- [二次开发]dede文章页面怎样显示作者的头像
dede在文章页面显示作者仅仅是显示其username,可是假如我想把dede改造成较为社交化的站点.我认为是有必要显示作者的头像的,可是官方并没有相应的模版标签. 在网上看到解决问题的办法基本上是直 ...
- 《Python 机器学习》笔记(四)
数据预处理--构建好的训练数据集 机器学习算法最终学习结果的优劣取决于两个主要因素:数据的质量和数据中蕴含的有用信息的数量. 缺失数据的处理 在实际应用过程中,样本由于各种原因缺少一个或多个值得情况并 ...
- git在IDEA中的使用
学习资料: http://blog.csdn.net/autfish/article/details/52513465 (关于提交的讲解) http://blog.csdn.net/ck443870 ...
- sequence.c
/* * sequence.c */ #include <stdio.h> #include <memory.h> /* * SM3算法产生的哈希值大小(单位:字节) */ # ...
- 每天一个Linux命令(57)rpm命令
rpm是一个功能十分强大的软件包管理系统. (1)用法: 用法: rpm [参数] [包名] (2)功能: 功能: 使得在Linux下安装.升级和删除软 ...
- 每天一个Linux命令(44)crontab命令
crontab命令被用来提交和管理用户需要周期性执行的任务,与windows下的计划任务类似. (1)用法: 用法: crontab [-u user] file cron ...