您的位置:首页 > 移动开发 > IOS开发

读《编写高质量iOS与OS X代码的52个有效方法》心得

2018-01-13 00:00 323 查看
摘要: 整本书共用52大个要点,每个要点介绍到位,对于提升有帮助

因为有些在方法中经常用到,比较熟悉,所以看起来非常快。有些在开发中细节的忽略,看了之后理解更深入了。

苹果开源网站:http://opensource.apple.com/source/,有很多博客都对一些源码进行了分析,下面

下面就对于:第12条理解消息转发机制和第37条理解“块”这一概念对自己的理解讨论一下:

一.消息转发机制

先来看一下例子:





新建一个对像:

RHC_Message *msg = [RHC_Message new];

发送消息:

[msg testMessage];

运行结果如下:



抛出异常了,下面来解释:

上面抛出异常是用到了消息转发机制,步骤如下:

1.OC 调用方法:

[msg testMessage],msg为接收者,testMessage为选择器,

2.转换为objc_msgSend函数如:objc_msgSend(msg,@selector(testMessage));

3.启用消息传递机制:本类中方法缓存列表查找方法,查找本类中方法列表,查找父类方法

4.如果消息在该类或父类找到,启用转发机制:

动态方法解析:

+(BOOL)resolveInstanceMethod:(SEL)selector

+(BOOL)resolveClassMethod:(SEL)selector

当动态方法解析没有实现或无法处理时,备援接收者:

-(id)frowardingTargetForSelector:(SEL)selector

当动态方法解析和备援接收者都没有进行处理的话:

-(void)forwardInvocation:(NSInvocation*)invocation(完整的消息转发,可以修改参数和选择子)

5.抛出异常:unrecognized selector sent to instance ****;

看一下resolveInstanceMethod方法

从开源库中下载objc4-723 找到objc_class.mm 可以看到:





消息转发总结:

1.若对象无法响应某个选择子,则进入消息转发流程

2.通过运行期的动态方法解析功能,我们可以在需要用到某个方法时再将其加入类中。

3.对象可以把其无法解读的某些选择子转交给其他对象来处理。

4.经过上面两步之后,如果还是没办法处理选择子,那就启动完整的消息转发机制。

开发中,从服务器拿到的json数据转模型会常用到OC的运行时(消息转发是运行时的一部分)。

二.块(Block)

先看之前我的分析:

http://blog.csdn.net/baitxaps/article/details/50723185

https://github.com/baitxaps/Block/blob/master/Block/block.mm

//三、Block的实质
/*
clang(LLVM编译器)具有转换为我们可读源代码的功能,通过:-rewrite -objc 选项就能将含有Block语法的
源代码变换为C++的源代码,说是C++,其实也公是使用了struct结构,其本质是C语言源代码
clang -rewrite-objc 源代码文件名
*/

//1.Block的实质
- (void)essenceBlock{

{
void (^blk)(void) = ^{
printf("block\n");
};
blk();
}

}

struct __block_imp1{
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};

#if __cplusplus
extern "C" {
#endif
struct __main_block_imp1_0{
struct __block_imp1 imp1;
struct __main_block_desc_0 *Desc;

__main_block_imp1_0(void *fp,struct __main_block_desc_0 *desc,int flags=0){
imp1.isa        = &_NSConcreteStackBlock;
imp1.Flags      = flags;
imp1.FuncPtr    = fp;  //fp:函数指针__main_block_func_0
Desc            = desc;//desc:静态全局初始化的__main_block_desc_0结构体实例指针
}
//......
/*
__main_block_imp1_0 结构体相当于基于objc_object结构体的OC类对象的结构体.另外,对其中的成员变量isa进行初始化:
imp1.isa  = &_NSConcreteStackBlock;
即_NSConcreteStackBlock相当于class_t结构实例,在将Block作为OC的对象处理时,关于该类的信息放置于_NSConcreteStackBlock中。
*/
};

#if __cplusplus
}
#endif

static void __main_block_func_0(struct __main_block_imp1_0 *__cself){
printf("Block\n");
}

static struct __main_block_desc_0{
unsigned long reserved;
unsigned long Block_size;
}__main_block_desc_0_DATA ={
0,
sizeof(struct __main_block_imp1_0)
};

int Main(){
//1.void (^blk)(void) = ^{printf("block\n");};
//栈上生成的__main_block_imp1_0 结构体实例的指针,赋值给__main_block_imp1_0 结构体指针类型的变量blk,
/*
struct __main_block_imp1_0 tmp = \
__main_block_imp1_0(__main_block_func_0,&__main_block_desc_0_DATA,0);
struct __main_block_imp1_0 *blk = &tmp;

//void (*blk)(void) = (void (*)(void))&__main_block_imp1_0((void *)__main_block_func_0,&__main_block_desc_0_DATA);
*/

//2.blk();
/*
(*blk->impl.FuncPtr)(blk);//函数指针调用函数
//((void(*)(struct __block_imp1 *))((struct __block_imp1 *)blk)->FuncPtr)((struct __block_imp1 *)blk);
*/
return 0;
}


块block心得总结:

开发中注意:

1.block副本:

_NSCondreteStackBLock(栈 从栈复制到堆)

_NSConcreteGlobalBlock (程序的数据区域 ,什么也不做)

_NSConcreteMallocBlock(堆 引用计数增加)

2.__block变量和对象.

如果在Block中使用附有__strong修饰符的对象类型自动变量,那么当Block从栈复制到堆时,该对象为Block所持有,这样容易引起循环引用

2017年年前计划看完以下书籍,但有些没有完成,自己应该反醒

1.代码整洁之道

2.TCP/IP 网络编程[韩]尹圣雨著

3.TCP/IP 详解卷2

4.Effiective java中文版 第2版

5.objc.io|objc 中国 函数式Swift

其中:

TCP/IP 网络编程[韩]尹圣雨著,非常适合入门级看;TCP/IP 详解卷2,想代码全过一遍,但由于其他原因,一直没有去执行 ;Effiective java中文版 第2版,看到第9章。

2018年勉励自己,继续努力
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  心得
相关文章推荐