Effective Objective-C 2.0 学习记录

  由于最近入职,公司安排自由学习,于是有时间将Effective Objective-C 2.0一书学习了一遍。由于个人知识面较窄,对于书中有些内容无法理解透彻,现将所学所理解内容做一遍梳理,将个人认为常用且重要的知识记录下来,以供日后参考。

  1.在类的头文件中尽量少引入其他头文件

  将头文件引入的时机尽量延后,在确有需要的时才引入(比如.m文件中)。因为头文件中引入其他类头文件,会增加编译时间(可能是现在运行硬件比较好,所所以对此点没啥感觉)。在头文件中若要使用其他类,则用"向前声明"-->@class + 类名。

  2.多用类型常量,少用#define预处理指令

  因为用预处理指令定义出来的常量不含类型信息,编译器只会进行查找替换,即使有人重新定义了常量值,编译器也不会产生警告。建议使用方法如下

//将#define
#define ANIMATION_DURATION 0.3
//用句代码表示
static const NSTimeInterval kAnimationDuration = 0.3;

这样不仅可以知道常量类型 还可以将数据局限于本类文件中使用

  3.用枚举表示状态、选项、状态码

  初级编写代码人员可能直接写出枚举,编写其状态

typedef enum PSPConnectionState{
    PSPConnectionStateDisconnected = 1,
    PSPConnectionStateConnecting,
    PSPConnectionStateConnected,
}PSPConnectionState;

初看直线好像并无不妥,但如果改变一下编写枚举的方式,写成如下所示

//单选状态枚举
typedef NS_ENUM(NSUInteger, PSPConnectionState){
    PSPConnectionStateDisconnected = 1,
    PSPConnectionStateConnecting,
    PSPConnectionStateConnected,
};
//复选状态枚举
typedef NS_OPTIONS(NSUInteger, PSPConnectionState){
    PSPConnectionStateDisconnected = 1 << 0,
    PSPConnectionStateConnecting = 1 << 1,
    PSPConnectionStateConnected = 1 << 2,
};

这样用NS_ENUM和NS_OPTIONS宏来定义枚举类型,并指明器底层数据类型,除了可以确保枚举是开发者所选的底层数据类型实现出来外,还能够方便其他开发人员查看和使用。另外注意在处理枚举类型时可以尽量使用switch语句,并且不要实现default分支,这样的话,在新加如枚举之后,编译器就会提醒开发者switch语句没有处理所有的枚举。

  4.在对象内部尽量直接访问实例变量

  直接访问实例变量由于不经过Objective-C的"方法派发"步骤,所以访问速度会比较快,但由于直接访问实例变量不会触发"键值观测"(KVO),因此建议读数据时直接通过实例变量来读,而写入数据的时候,则通过属性来写(点语法)。当然对于惰性加载的属性,需要通过属性来读取数据。

  5.理解消息转发机制

  消息转发分为两大阶段:第一阶段先征询接受者所属类,看其是否能动态添加方法,以处理当前这个“未知的选择器”,这个叫做“动态方法解析”。第二阶段涉及“完整的消息转发机制”。消息整体转发流程通过下图来表示

这里模拟在动态方法解析中添加方法 下面为代码示例

=======.h文件中=========
@interface BQAutoDictionary : NSObject

//随意创建的属性
@property (nonatomic, copy) NSString *string;
@property (nonatomic, strong) NSNumber *number;
@property (nonatomic, strong) NSDate *date;
@property (nonatomic, strong) id opaqueObject;

@end
=======.m文件中=========
@interface BQAutoDictionary()

@property (nonatomic, strong) NSMutableDictionary *backingStore;

@end

@implementation BQAutoDictionary
//不动态生成get,set方法
@dynamic string, number, date, opaqueObject;

- (instancetype)init
{
    self = [super init];
    if (self) {
        _backingStore = [NSMutableDictionary new];
    }
    return self;
}
+ (BOOL)resolveInstanceMethod:(SEL)sel{
    //获得无法处理消息名字
    NSString *selectorString = NSStringFromSelector(sel);
    NSLog(@"%s",__func__);
    //动态添加set和get方法
    if ([selectorString hasPrefix:@"set"]) {
        /**
         *  动态添加set方法
         *  @param self 类别
         *  @param sel  方法选择器
         *  @param IMP  需要增加的方法
         */
        class_addMethod(self, sel, (IMP)autodictionarySetter, "[email protected]:@");
    }else{
        class_addMethod(self, sel, (IMP)autodictionaryGetter, "@@:");
    }
    return YES;
    //若不能处理消息时需要返回下面方法,进行消息转发
    //return [super resolveInstanceMethod:sel];
}
id autodictionaryGetter(id self, SEL _cmd){
    //得到实例中的字典
    BQAutoDictionary *typedSelf = (BQAutoDictionary *)self;
    NSMutableDictionary *backingStore = typedSelf.backingStore;
    //根据选择器获取名字
    NSString *key = NSStringFromSelector(_cmd);
    NSLog(@"Getter Name = %@",key);
    //返回值
    return [backingStore objectForKey:key];
}
void autodictionarySetter(id self, SEL _cmd, id value){
    BQAutoDictionary *typedSelf = (BQAutoDictionary *)self;
    NSMutableDictionary *backingStore = typedSelf.backingStore;
    NSString *selectorString = NSStringFromSelector(_cmd);
    NSMutableString *key = [selectorString mutableCopy];
    NSLog(@"Setter Name = %@",key);
    //移除‘:’字符
    [key deleteCharactersInRange:NSMakeRange(key.length - 1, 1)];
    //移除‘set‘字符
    [key deleteCharactersInRange:NSMakeRange(0, 3)];
    //首字母改小写
    NSString *lowercaseFirstChar = [[key substringToIndex:1] lowercaseString];
    [key replaceCharactersInRange:NSMakeRange(0, 1) withString:lowercaseFirstChar];
    if (value) {
        [backingStore setObject:value forKey:key];
    }else{
        [backingStore removeObjectForKey:key];
    }
}
@end

  6.用前缀避免命名空间冲突

  由于开发人员文件整合的时候经常出现命名重复的问题,但由于Objective-C没有命名空间机制。因此避免文件重命名的办法就是:为所有的名称都加上适当的前缀。Apple宣城其保留使用所有“两字母前缀”的权利,所以我们选用的前缀应该是三个字母的!

  7.尽量使用不可变对象

  属性是read-write,这样出来的类都是可变的。一般情况下我们要建模的数据未必都需要改变。比如网络服务的数据请求后,我们只是将数据就行展示。当然若某属性仅可于对象内部修改,则可在延展中将其属性由readonly扩展为readwrite。示例如下

=====.h文件======
@interface BQAutoDictionary : NSObject
@property (nonatomic, readonly) NSString *name;
@end
=====.m文件======
@interface BQAutoDictionary ()
@property (nonatomic, readwrite, copy) NSString *name;
@end

  8.在dealloc方法中只是放引用并解除监听

  对象在经历器生命周期后,最终会被系统回收,这时就要执行dealloc方法,因为此时对象已处于回收状态,因此不应再此方法内再做其他事情。只需要在里面释放指向其他对象的引用,并取消原来订阅的“键值观测”(KVO)或NSNotificationCenter等通知!注意对象所拥有的其他非Objective-C对象需要在这里手动释放,如果是手动管理内存,那么在最后还需要调用[super dealloc]

  9.多用派发队列,少用同步锁

  在以前的代码编写中,对于线程安全问题通常采用的做法是直接加线程锁。加线程锁的方法很好不过也有其缺陷,比如说,在极端情况下,同步块回导致死锁,另外其效率也不够高。这里就需要引入一个简单而高效的办法就是使用“串行同步队列”,用法如下

_syncQueue = dispatch_queue_create("PSP", 0);

- (NSString *)name{
    __block NSString *localName;
    dispatch_sync(_syncQueue, ^{
        localName = _name;
    });
    return localName;
}
- (void)setName:(NSString *)name{
    dispatch_sync(_syncQueue, ^{
        _name = name;
    });
}

当然还有一种更高效的方法用栅栏(barrier),栅栏块必须单独执行,不能与其它块并行(只对并发队列有意义)

//并行队列
_syncQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//用同步
- (NSString *)name{
    __block NSString *localName;
    dispatch_sync(_syncQueue, ^{
        localName = _name;
    });
    return localName;
}
//利用异步栅栏块
- (void)setName:(NSString *)name{
    dispatch_barrier_async(_syncQueue, ^{
        _name = name;
    });
}

  10.构建缓存时选用NSCache而非NSDictionary

  在进行网络请求是如何缓存,大部分程序员可能是直接使用NSDictionary,其实NSCache类更好,它是Foundation框架专为处理这种任务而设计的NScache胜过NSDicitionary之处在于,当系统资源将要耗尽时,它可以自动删除缓存。如果采用普通的字典,那么就需要自己编写挂钩(我也不懂啥意思)。此外NSCache还会先行删除“最久未使用的”对象。另外还有个类叫做NSPurgeableData(NSMutableData子类),和NSCache搭配起来使用效果很好。具体使用方法可以自行百度!

  以上便是个人觉得需要整理的知识,若其中有什么错误之处,请大家指出,谢谢!

    

时间: 2024-10-31 05:15:24

Effective Objective-C 2.0 学习记录的相关文章

tempo 2.0 学习记录

最近在做项目时使用了tempo,感觉还不错,但是发现网上对于tempo 2.0 的介绍比较少,我也是在GitHub才找到了比较完整的使用说明,我也简单记录一下自己的使用过程,重新学习一下tempo 2.0 , 不喜勿喷,喜欢看英文的朋友请移步tempo 2.0 英文说明 . 1.引入tempo.js <script src="js/tempo.js" type="text/javascript"></script> 2.准备数据Data(标准

html5.0学习记录(一)——可拖动视频播放器

最近自己在重新学习html5新特性,了解到有视频标签和拖动标签,于是自己用这两个特性写了一个小demo,主要功能就是可以通过拖动视频来直接播放.效果图如下: 页面使用了<video>标签和drag,drop方法.左侧是动态渲染的视频列表,里面title包含着视频路径信息,右侧是视频播放器. js代码: // 拖拽开始 function dragStart() { let e = window.event; e.dataTransfer.setData('video', e.target.tit

AngularJS 2.0 学习记录(一)

开始认真学习ng2了,之前看了一下typescript,没有太大感触,还是直接练手学习得快.

.net core 2.0学习记录(一):搭建一个.Net Core网站项目

.Net Core开发可以使用Visual Studio 2017或者Visual Studio Code,下面使用Visual Studio 2017搭建一个.net Core MVC网站项目. 一.新建项目 二.选择 Web应用程序(模型视图控制器) 三.项目结构和之前的比对还是有很大的不同,wwwroot用来存放前端的一些静态资源(css/js/image),以前是通过Nuget来下载前后端包,现在前端包使用Bower下载,后端的包的使用Nuget下载 四.运行 .net core项目调试

Spark2.0学习记录

Hadoop与Spark的关系: ------------------- Spark 与mapReduce的区别: mapReduce和spark的内存结构: ------------------- spark替代hive区别: spark替代hive的查询引擎 ------------------- Spark Steaming 与 Storm 的区别: Spark Steaming 与 Storm模型对比 原文地址:https://www.cnblogs.com/gxyandwmm/p/11

Lucene.net(4.8.0) 学习问题记录五: JIEba分词和Lucene的结合,以及对分词器的思考

前言:目前自己在做使用Lucene.net和PanGu分词实现全文检索的工作,不过自己是把别人做好的项目进行迁移.因为项目整体要迁移到ASP.NET Core 2.0版本,而Lucene使用的版本是3.6.0 ,PanGu分词也是对应Lucene3.6.0版本的.不过好在Lucene.net 已经有了Core 2.0版本(4.8.0 bate版),而PanGu分词,目前有人正在做,貌似已经做完,只是还没有测试~,Lucene升级的改变我都会加粗表示. Lucene.net 4.8.0 https

stl学习记录

Effective STL 中文版学习记录 条款4 判断容器是否为空 使用empty而不是size().size()操作在实现上不是一个时间常数操作条款5 尽量使用区间成员函数代替它们的单元素兄弟.STL实现中,区间范围显示比单个循环操作更优化 条款7:当使用new得指针的容器时,记得在销毁容器前delete那些指针vc2008下 运行代码 可以看到 该程序内存不断增加// 1111111.cpp : 定义控制台应用程序的入口点.// #include "stdafx.h" #incl

Java设计模式学习记录-迭代器模式

前言 这次要介绍的是迭代器模式,也是一种行为模式.我现在觉得写博客有点应付了,前阵子一天一篇,感觉这样其实有点没理解透彻就写下来了,而且写完后自己也没有多看几遍,上次在面试的时候被问到java中的I/O的各种实现用到了什么设计模式,我愣是想半天没想出来了,人家还给提示了我也没想出来,最后还是面试官给出的答案,是装饰模式,听到答案后就恍然大悟了,前两天刚看了装饰模式,还写下了I/O操作中的各种类都是用到了装饰模式,后来想想两方面原因造成的当时没回答出来,一是面试时紧张就容易想不起来,二是对设计模式

学习记录:数据结构与算法分析c++版

数据结构与算法分析c++版 学习记录 一.绪论 1.数据结构的必要性 计算机程序被设计出来的目的不仅仅是为了计算,同时其也要完成数据的提取和检索任务,并尽可能地高效快速.在这个意义下,数据结构和算法分析作为程序的核心,就显得尤为重要.如何利用数据结构和算法,设计出简单易懂,并且高效地利用计算机资源的程序是这门课的核心议题. Def    一个算法被称为有效的(effective),如果其能在计算机的资源限制下解决相应问题:这些限制通常包括计算机储存量限制,以及算法运行的时间限制.    算法的消