Effective Objective-C 2.0 初读小结

  • 1.对于OC中的对象声明例如NSObject *obj1 = [NSObject new];, obj1这个指针变量是分配在栈上的, 他指向的是这一个分配在堆上面的实例对象, 如果进行下面的赋值操作NSObject *obj2 = obj1;,那么并没有新生成一个实例对象, 只是在栈上分配了一个新的指针变量obj2, 而obj2和obj1指向的实例对象是同一个.
  • 2.关于文件头文件的引入问题, 一般情况下不建议在A.h文件中引入其他的B.h文件, 因为在别人引入A.h的时候, 同时也引入了B.h文件, 增加不必要的文件耦合和编译时间, 一般在.h文件中使用前向声明@class B, 而在.m文件中才真的引入头文件, 当然对于protocol不能使用前向声明, 如果将protocol放在了另一个.h文件中, 那么就必须要引入这个头文件了.
  • 3.尽量使用字面量语法来初始化字符串, 数组, 字典等, 因为字面量语法其实是一种语法糖, 使用它可以让代码可读性更高, 当然对于一些必须要使用到初始化方法的时候字面量语法就不好用了.例如:
  • NSString *str = @"string";
    NSArray *arr = @[obj1, obj2];
    arr[1]// 读取使用下标而尽量不使用对应的函数...
    [array setObject:(nonnull id) atIndexedSubscript:(NSUInteger)]
  • 4.少用#define来定义常量, 因为宏定义只是简单的代码替换, 并没有类型判断, 不便于我们阅读判断, 同时宏定义可以被覆盖, 当别人引入了我们的头文件的时候, 可能会覆盖我们里面定义的宏, 带来很麻烦的调试, 我们应该使用C语言风格的const,static, extern相结合来定义常量
    /// 使用static 和const 定义文件内部的常量 一般使用k开头命名
    static float const kAnimationTime = 2.0f;
    /// 使用const定义全局的常量, 在其他文件中可以通过 extern float const kAnimationTime引入使用, 一般不用k开头命名, 而使用class名字
    float const CustomAnimationTime = 2.0f;
  • 5.用好枚举, 使用枚举来表示选项, 状态码, 可以让代码更清晰, 这个在系统的API中也经常看到, 比如按钮的状态, autoresizing... , 例如如果你需要用一些状态码来表示网络请求的结果: 你可能会有两种方法
      1. 定义一个整形变量, 然后说明, 不同的整数代表不同的状态, 那么这样对于开发就很不方便, 必须得很清楚并且很正确的输入对应的整数才能表示相应的状态, 那么就很容易出错, 和不便于维护int statusCode;if (statusCode == 200) { }/// 请求成功else if () ....2. 使用枚举, 对不同的状态定义不同的名字, 这样就很清晰方便了, 当然定义的时候使用NS_ENUM比使用enum要`好`
    typedef NS_ENUM(NSInteger, ErrorCode) {ErrorCodeNotFind,ErrorCodeLostConnection,ErrorCodeUnknow
    };
    显然上面你应该选用枚举, 同时还有一种情况就是, 定义多选项, 这个你是会把他们都放进一个数组中么?? 当然不要这样做, 这个时候也应该使用枚举来定义, 不过会有一点的小技巧, Apple对这种进行了一个包装, 使用NS_OPTIONS而不是enum
    typedef NS_OPTIONS(NSInteger, ErrorOptions) {ErrorOptionsNone = 0,ErrorOptionsOne = 1 << 0, ///左移操作    --- 1 --- 0001ErrorOptionsTwo = 1 << 1,               --- 2 --- 0010ErrorOptionsThree = 1 << 2              --- 4 --- 0100
    };
    因为上面定义的枚举值都为2的整数次幂值, 所以后面就可以使用位操作符 与(&)和或(|)来进行选项的筛选
    ErrorOptions options = ErrorOptionsOne | ErrorOptionsTwo; //--- 0011if (options & ErrorOptionsOne) {// ErrorOptionsOne// 结束判断后面}else if (options & ErrorOptionsTwo) {// ErrorOptionsTwo// ...}else {// ...}
  • 6.需要遍历操作的时候, 尽量不要用C语言风格的for遍历, 而是采用OC的 for-in方式的快速枚举, 当然使用block的方式来遍历未必不是更好的一种方式, 尤其是遍历字典的时候.
  • 7.需要缓存的时候使用NSCache而不要使用NSArray或者NSDictionary, 因为使用NSCache来进行缓存当内存不足的时候系统会自动清理缓存, 并且会首先清理缓存时间较长的东西, 如果使用NSArray或者NSDictionary就没有这个福利了
  • 8.不要在load方法里面执行耗时的操作, 因为这个时候会阻塞当前的线程, 如果是主线程被阻塞, 那么...就不能接受用户的响应, 同时不要在load方法里面使用其他的类和调用函数, 因为这个时候程序是脆弱的, 有可能使用的class还没有被加载到系统中来, 当然使用Foundation里面的NSString...这些是没有问题的
  • 9.initialize这个方法在文档中写明了是在第一次使用这个类的时候才会调用一次(懒加载), 但是需要注意的是, 如果父类中实现了initialize这个方法, 而子类中没有实现这个方法, 当初始化子类的时候, 父类的这个initialize方法是会被调用多次的(消息转发机制), 比如
        ZJChildClass类里面没有重写initialize方法, 但是他的父类重写了, 所以在初始化ZJChildClass的时候, 父类的initialize会被调用两次, 即会打印两条@interface ZJBaseClass : NSObject@end@implementation ZJBaseClass+ (void)initialize {NSLog(@"加载一次-----");}@end@interface ZJChildClass : ZJBaseClass@end
    所以一般都是这样来重写initialize方法的, 保证只会像我们期望的那样调用一次
      + (void)initialize {if (self == [ZJBaseClass class]) { /// 不能用 [self class]NSLog(@"加载一次-----");}}
  • 10.对只需要执行一次的代码使用dispatch_once, 这样可以保证线程安全, 并且只执行一次, 最常见的是用来实现单例
    + (instancetype)sharedInstance {static Object *sharedInstance = nil;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{sharedInstance = [self new];});return sharedInstance;
    }
  • 11.多用GCD少用NSObject的一些performSelector等方法, 因为使用performSelector这种方式可能会造成内存泄漏, 一般情况下使用GCD都可以完成, 比如dispatch_after来实现延时后执行
  • 12.使用NSTimer的时候要特别注意内存泄漏的问题, 因为NSTimer会持有目标对象, 很容易造成循环引用的问题, 也许你会想到在这个目标对象的dealloc里面让NSTimer失效(调用 invalidation 并且置为nil), 但是这根本就没有用, 因为循环引用的原因, 根本就不会调用dealloc方法, 所以在里面销毁是没有用的, 需要在对象被销毁之前手动销毁计时器

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/247982.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

APS系统对制造企业到底有多重要?看完这5点你就明白了

第一个问题&#xff1a;需要APS吗&#xff1f; APS是否重要&#xff0c;不能从其所体现的软件工具或系统角度来说&#xff0c;而应该从业务角度来说。对于制造工厂和车间的运行而言&#xff0c;计划是核心的业务。就如同那句俗话说的&#xff0c;没有规矩不成方圆&#xff0c;领…

Node — 第九天 (大事件项目接口实现三)

文章管理接口 设计数据表 添加文章接口 编写接口&#xff0c;使用postman模拟提交formdata类型的数据 在article.js 中&#xff0c;加入 /add 路由 postman模拟提交formdata类型的数据 multer处理文件上传 下载安装multer 加载模块 const multer require(multer) 配置上…

Python之爬虫-段子网

Python之爬虫-段子网 https://ishuo.cn #!/usr/bin/env python # -*- coding:utf-8 -*- import re import requestsresponse requests.get(https://ishuo.cn) data response.text print(data) r re.findall(<div class"content">(.*?)</div>,data) f…

Node — 第九天 (ES6降级 and 发布属于自己的[第三方模块]包)

ES6降级处理 因为 ES 6 有浏览器兼容性问题&#xff0c;可以使用一些工具进行降级处理&#xff0c;例如&#xff1a;babel 降级处理 babel 的使用步骤 安装 Node.js命令行中安装 babel配置文件 .babelrc运行命令&#xff0c;完成降级 项目初始化 (项目文件夹不能有中文) npm …

Vue — 第一天(极速入门)

基本介绍 vue是什么 目标&#xff1a;了解vue的一些基础概念。 官方网站&#xff1a; https://cn.vuejs.org/ vue是&#xff1a;渐进式javascript框架。 两组概念 &#xff08;1&#xff09;框架 库。只提供一些API给开发者使用。jquery 是一个js库框架。拥有自己的规则和…

python类和实例化

简答介绍类和实例python是面向对象的语言&#xff0c;最主要的就是类和实例&#xff0c;类是抽象的模版创建一个类class Studen(object),class 后接类名&#xff0c;定义的类名大些字母开头&#xff0c;object为类的继承&#xff0c;没有合适的继承类用object类&#xff0c;这是…

pjsip库分析

http://blog.chinaunix.net/space.php?uid287570&doblog&cuid728411 如果你对SIP/VoIP技术感兴趣,哪希望你不要错过:),如果你对写出堪称优美的Code感兴趣,那么你也不可错过:)这期间我想分析一下一个实际的协议栈的设计到实现的相关技术,算是自己的一个学习经历记录.最…

Vue — 第二天(v-model和过滤器)

VUE-02-v-model和过滤器 昨日反馈与回顾 代码仓库的问题 不要修改你克隆下来的仓库中任意代码&#xff0c;否则&#xff0c;下次pull时&#xff0c;可能会报错&#xff0c;从而得到不到最新的代码。 如果已经遇到了这个冲突&#xff1a; 解决冲突(git 中解决冲突)把关键代码…

Count

题目链接&#xff1a;点这里 题目意思&#xff1a;令f(x)表示<x的正整数中与x互质的数的平均数*2&#xff0c;求sigma(f(i)^k),L<i<R Solution: 首先&#xff0c;我们定义\(S(x)\sum_{gcd(a,x)1}a\)&#xff0c;因为gcd(a,x)1&#xff0c;所以对于任意a&#xff0c;满…

牛人iOS开发系列--音频播放、录音、视频播放、拍照、视频录制

概览 随着移动互联网的发展&#xff0c;如今的手机早已不是打电话、发短信那么简单了&#xff0c;播放音乐、视频、录音、拍照等都是很常用的功能。在iOS中对于多媒体的支持是非常强大的&#xff0c;无论是音视频播放、录制&#xff0c;还是对麦克风、摄像头的操作都提供了多套…

Vue — 第三天(计算属性和json-server)

计算属性 使用场景 如果一个结果需要依赖data中的数据&#xff0c;但是需要经过一些逻辑处理&#xff0c;才能得到你想要的数据。此时就可以使用计算属性。 例如&#xff1a;要对给定的字符串做翻转处理之后再来显示。 <div id"app"><!-- 此处逻辑复杂 …

JQuery的ready函数与JS的onload的区别详解

JQuery的ready函数与JS的onload的区别&#xff1a;1.执行时间window.onload必须等到页面内包括图片的所有元素加载完毕后才能执行。$(document).ready()是DOM结构绘制完毕后就执行&#xff0c;不必等到加载完毕。 2.编写个数不同window.onload不能同时编写多个&#xff0c;如果…

Vue — 第四天(components组件)

问题导入 下面的代码是一个折叠面板的效果。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Docu…

iOS开发常用的RGB色值和宏

iOS中RGB常用的色值,同时可将对颜色的设置定义成宏,方便开发应用,如: // name 颜色相关 // 参数格式为&#xff1a;0xFFFFFF #define kColorWithRGB(rgbValue) \ [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16)) / 255.0 \ …

防火墙综合实验

防火墙技术综合实验 一、实验目的&#xff1a;本次实验是将多种访问控制列表以及防火墙部分的知识做一个汇总 二、实验内容 A&#xff1a;Established控制列表 拓扑图 配置步骤 1:配置各端口ip地址&#xff0c;配置登陆密码 R4: 登陆账号&#xff1a;ys 密码&#xff1a;123 2:…

iOS获取当前设备型号等信息总结 包含iPhone7和iPhone7P

#include <sys/types.h> #include <sys/sysctl.h>//获得设备型号(NSString *)getCurrentDeviceModel {int mib[2];size_t len;char *machine;mib[0] CTL_HW;mib[1] HW_MACHINE;sysctl(mib, 2, NULL, &len, NULL, 0);machine malloc(len);sysctl(mib, 2, mac…

Vue — 第五天(路由)

前端路由 问题导入 在前面完成的资产管理案例中&#xff0c; 我们是把列表区域和添加表单区域实现在了一个区域。当页面功能比较复杂时&#xff0c;我们需要它们拆分开来&#xff1a;一个页面中只显示一个区域。 一个比较直观的解决方案是把它们分别做成两个独立的网页文件&…

获取网络时间,在不同时间触发事件

<!DOCTYPE html><html lang"en"><head>   <meta charset"UTF-8">   <title>时间事件</title></head><body></body><script> var int_timenew Date();//使用Date获取网络时间;   functi…

iOS获取手机的IP地址

1.添加这五个库&#xff08;在联网的情况下&#xff09; #import <sys/socket.h> #import <sys/sockio.h> #import <sys/ioctl.h> #import <net/if.h> #import <arpa/inet.h>2.写一个方法 - (NSString *)getDeviceIPIpAddresses {int sockfd soc…

Vue — 第六天(vue-cli-介绍)

vue-cli-介绍 vue-cli是官方提供的开发vue项目的脚手架工具。 脚手架是为了保证各施工过程顺利进行而搭设的工作平台。 在开发过程中&#xff0c;脚手架工具是有用的&#xff0c;开发完成&#xff08;项目上线&#xff09;&#xff0c;它就没有用了。 vue-cli可以提供基于vue项…