类型常量:使用类型常量代替#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. 一直没有敢发的NOIP2018游记

    一直没有敢发的NOIP2018游记 NOIP2018游记 教练说知足是最好的,尽吾志而也不能及者,可以无悔矣.在这次考试中的表现令我还是十分满意的.(笑) D1 T0 我配置背得感觉很好,我考场上直接 ...

  2. python并发之IO模型(一)

    事件驱动模型 协程:遇到IO操作就切换. 但什么时候切回去呢?怎么确定IO操作完了? 很多程序员可能会考虑使用“线程池”或“连接池”.“线程池”旨在减少创建和销毁线程的频率,其维持一定合理数量的线程, ...

  3. spring中配置缓存—ehcache

    常用的缓存工具有ehcache.memcache和redis,这里介绍spring中ehcache的配置. 1.在pom添加依赖: <!-- ehcache 相关依赖 --> <de ...

  4. java bio 之聊天室

    最近在复习java io相关知识 ,发现很多细节之前没学习到位,原理也没吃透,只能感叹本人愚钝. 复习到bio,顺手写了个简单的聊天室功能,并和大家分享下. 服务端: package io.QQ聊天室 ...

  5. java switch case 枚举类型的反编译结果

     package com.example.demo; import java.io.PrintStream;  // Referenced classes of package com.example ...

  6. Amazon2014在线笔试 第三题

    问题描述: 算法分析: s1:层数对齐:分别求两个数所在的层(l1,l2),把层数大的(假设l2>l1)先往上找父节点,从而对齐到l1层: s2:两个数同时往上找, 直到找到公共的父节点(一定能 ...

  7. Google Cloud Platfrom中使用Linux VM

    Linkes https://cloud.google.com/compute/docs/quickstart-linuxhttps://console.cloud.google.com/comput ...

  8. 使用idea2016导出web项目war包

    第一步配置Web Application:Exploded(已经配置的可以跳到第二步): 打开project structure(默认的快捷键是Ctrl+Alt+Shift+S),依次选择Artifa ...

  9. 【leetcode刷题笔记】Palindrome Partitioning II

    Given a string s, partition s such that every substring of the partition is a palindrome. Return the ...

  10. Shell编程之while循环和until循环

    一.当型和直到型循环 1.while循环语句 while < 条件表达式 > do 指令... done while循环执行流程对应的逻辑图 2.until循环语句 until < ...