Effective Objective-C学习第一周

OC的起源

OC是一种消息型语言,使用的是“消息结构”而非“函数调用”,由smalltalk演化而来。使用消息结构的语言运行时执行的代码由运行环境来决定,而使用函数调用的语言由编译器决定。

什么是引用计数

OC将堆内存管理抽象出来了。不需要使用malloc或者free来分配或释放对象所占的内存。OC运行期环境把这部分工作抽象成一套内存管理架构,名为“引用计数”。

  • OC为C语言添加了面向对象特性,是其超集。OC使用动态绑定的消息结构,也就是说在运行的时候才会检查对象类型。接收一条消息后,究竟应执行哪种代码,由运行期环境而非编译器来决定。

向前声明某类

当编译一个A类的文件时,想要引入B类,但是不需要知道B类的全部细节,只需要知道有一个类叫B类,可以使用:

@class B;

但是如果要在A类的实现文件中使用B,则需要使用import声明,因为要使用它就要知道B类的所有细节。
这样做延后了引入头文件的时机,只有在确有需要时才引入,这样就可以减少类的使用者所需引入的头文件数量,减少编译时间。
向前声明同样可以解决两个类互相引用的问题。在两个类中互相引用对方的头文件,就会造成“循环引用”。当解析一个头文件时,会发现它引用了另一个头文件,而那个头文件又回头引用了第一个头文件。使用#import而非#include虽然不会导致死循环,但是会使得两个类中有一个无法被正常编译。
如果你写的类继承自某个超类,则必须引入定义那个超类的头文件,同理如果要声明你写的类遵从某个协议,那么该协议必须有完整定义,且不能向前声明。因为向前声明只是声明某个协议的存在,而此时编译器却需要知道该协议的具体定义。

  • 除非确实有必要,否则不要引入头文件。一般来说应在某个类的头文件中使用向前声明来提及别的类,并在实现文件中引入那些类的头文件。这样做可以降低类之间的耦合。
    有时无法使用向前声明,比如要声明某个类遵循一项协议。这种情况下尽量把“该类遵循某项协议”的这条声明放在分类中。如果不行的话就把协议单独放在一个头文件中然后引入。

多用字面量语法

使用字面量语法可以缩减代码长度,使其更为易读。
NSString:

NSString *str = @...;

NSNumber:

NSNumber *num = @1;

NSArray:

NSArray *arr = @[@1, @2, @3];
NSString *two = arr[1];

NSDIctionary:

NSDictionary *dict = @{@1: @“one”, @2: @“two”, @3: @“three”};
NSString *two = dict[@2];

NSMutableDictionary和NSMutableArray:

//字面量语法修改可变数组或者字典中的元素时可这样修改
mutableArray[1] = @2;
mutableDictionary[@3] = @4;

在数组中使用字面量语法时,倘若我们放入数组的元素是变量,其中一个变量为nil,那么编译器会报出异常,方便我们及时发现问题。但是如果使用的不是字面量语法,比如NSArray *arr = [NSArray arrayWithObjects: obj1, obj2, obj3, nil]; 在这个数组中如果obj2为nil,那么arr的值就会只有obj1,它不会报出异常,这是因为arrayWithObjects方法处理参数时发现nil就停止了,这也导致我们无法及时发现问题。字典同理。
因此,使用字面量语法也有助于我们快速发现问题。

字面量语法的局限性

字面量语法有个限制就是:除了字符串以外,所创建的对象必须属于Foundation框架才行。意思是自定义的这些类的子类是不能用字面量语法的。
使用字面量语法创建出来的字符串、数组、字典对象都是不可变的。若想要可变版本,需要:

NSMutableArray *mutableArray = [@[@1, @2, @3, @4]mutableCopy];
  • 应该使用字面量语法来创建字符串、数组、数值、字典。与常规方法相比。字面量语法更加简明扼要。
    应该通过取下标操作来访问数组下标或者字典中的键对应的元素。
    用字面量语法创建数组或字典时,若值中有nil,则会抛出异常。

多使用常量,少使用#define

定义常量应用static const,这样方式定义的常量包含类型信息,可以清楚的了解常量的含义。
定义的常量不应该放在头文件里。如果不打算公开某个常量,则应该将其定义在实现文件里。
变量一定要同时用static和const声明,如果试图修改由const修饰符所声明的变量,那么编译器就会报错。
有时候需要对外公开某个常量,比如使用通知传值的时候要用一个对象来派发通知,然后让其他接收通知的对象来注册通知完成传值。在派发通知的时候需要使用一个字符串来表明这个通知的名称,这个名称就可以声明为一个外界可见的常值变量。这样注册者就无需知道实际字符串的值,只需要以常值变量来注册自己想要接收的通知就行。这一类常量应该放在“全局符号表”中,以便可以在定义该常量的编译单元之外使用。
定义在全局符号表中:

extern NSString *const stringConst;
NSString *const stringConst = @“value”;   
//在上面的代码中,stringConst是一个指针常量,指向NSString对象。                                                                                                                                                                                                                                                                                                                                                                                                             
  • 不要用预处理指令定义常量。这样定义出来的常量不含类型信息,编译器只是会在编译前据此执行查找与替换操作。即使有人重新定义了常量值,编译器也不会产生警告信息,这将导致应用程序中的常量值不一致。
    在实现文件中使用static const来定义“只在编译单元内可见的常量”,由于此类常量不在全局符号表中,所以无须为其命名加前缀。
    在头文件中使用extern来声明全局变量,并在相关实现文件中定义其值。这种常量要出现在全局符号表中,所以其命名应该加一区隔,通常用与之相关的类名做前缀。

用枚举类型

在以一系列常量来表示错误状态码或可组合选项时,宜用枚举为其命名。
定义枚举的语法:

enum connectionState state = disconnected;
enum connectionState {disconnected,connected,connecting,
};
typedef enum connectionState connectionState;
connectionState state = disconnected;

可以指明用何种“底层数据类型”来保存枚举值的变量。因此这样做就可以向前声明枚举变量。若不指明底层数据类型就不可以向前声明,因为编译器不清楚底层数据类型的大小,不知道要给它分配多少空间。
指定底层数据类型:

enum connectionState: NSInteger{...};

在向前声明时指定底层数据类型:

enum connectionState: NSInteger;

不使用编译器分配的序号,使用自定义指定的值:

enum connetcionState {//将disconnected的值设为1,而不是编译器指定的0,这样接下来几个枚举的值都会是上一个的值+1disconnected = 1,connected,connecting,
};

定义选项时可以通过枚举组合选项,各选项之间通过“按位或操作符”来组合。

  • 应该用枚举来表示状态机的状态、传递给方法的选项以及状态码等值,给这些值起个易懂的名字。
    如果把传递给某个方法的选项表示为枚举类型,而多个选项又可以同时使用,那么就将各选项值定义为2的幂,以便通过按位或操作将其组合起来。
    用NS_ENUM与NS_OPTIONS宏来定义枚举类型,并指明其底层数据类型。这样做可以确保枚举是用开发者所选的底层数据类型实现出来的,而不会采用编译器所选的类型。
    在处理枚举类型的switch语句中不要实现default分支,这样的话,加入新枚举之后,编译器就会提示开发者switch语句并未处理所有枚举。

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

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

相关文章

Docker教程 Dockerfile 标签介绍

docker commit 也可以用来构建镜像,但是并不推荐。相反,更推荐使用dockerfile与docker build命令来构建镜像,Dockerfile使用基本的基于DSL(Domain Specific Language)语法的指令来构建Docker镜像。Dockerfile构建镜像更具备可重复性、透明性以…

MobaXterm连接服务器步骤

双击该软件 选择Session 点击SSH 填写服务器的IP地址、服务器的用户名称、Port这个端口号一般都是这个,但有些可能例外,自己注意一下,最后点击OK就行 这个五角星点击一下,就可以看到您自己刚才的配置。 鼠标左键双击&…

第 12 章 多路查找树

文章目录 12.1 二叉树与B 树12.1.1 二叉树的问题分析12.1.2 多叉树12.1.3 B 树的基本介绍 12.2 2-3 树12.2.1 2-3 树是最简单的 B 树结构, 具有如下特点:12.2.2 2-3 树应用案例12.2.3 其它说明 12.3 B 树、B树和 B*树12.3.1 B 树的介绍12.3.2 B 树的介绍12.3.3 B树的介绍12.3.4…

uniapp-x uts 介绍

uts 是什么 uts,全称 uni type script,是一门跨平台的、高性能的、强类型的现代编程语言。 它可以被编译为不同平台的编程语言,如: web平台,编译为JavaScriptAndroid平台,编译为KotliniOS平台&#xff0…

无root权限安装git-lfs(linux版)

首先给大家看一下官方链接:安装 Git Large File Storage - GitHub 文档 git-lfs/INSTALLING.md at main git-lfs/git-lfs (github.com) 直接用这个命令好啦~绕了一大圈 conda install git #yum install git 以下是手动安装 接下来是我的步骤: 首先在…

深入理解 Spark(四)Spark 内存管理模型

Spark 中的内存管理和资源管理模型 Executor 进程作为一个 JVM 进程,其内存管理建立在 JVM 的内存管理之上,整个大致包含两种方式:堆内内存和堆外内存。 一个 Executor 当中的所有 Task 是共享堆内内存的。一个 Work 中的多个 Executor 中的…

如何简单的使用文心一言(高级版)(中国版ChatGPT)

文心一言API高级版使用 一、百度文心一言API(高级版)二、使用步骤1、接口2、请求参数3、请求参数示例4、接口 返回示例5、智能生成API代码 三、 如何获取appKey和uid1、申请appKey:2、获取appKey和uid 四、重要说明 一、百度文心一言API(高级版) 基于百度文心一言语言大模型的…

[NAND Flash 5.4] QLC 闪存给SSD主控带来了很大的难题?

依公知及经验整理,原创保护,禁止转载。 专栏 《深入理解NAND Flash》 <<<< 返回总目录 <<<< 前言 世界各大主流闪存厂商,如美光、海力士、铠侠和长江存储积极致力于QLC的研发,并相继推出了QLC SSD产品。随着技术的不断进步,人们普遍担心的QLC擦…

Elasticsearch 快速入门指南【总结记录】

本文将介绍一些基本概念&#xff0c;帮助您快速入门使用Elasticsearch。 一、概述 ES用来解决什么问题&#xff1f;Elasticsearch是解决海量数据&#xff08;已经存在的数据&#xff09;全文检索的不二只选。 Elasticsearch是一个基于Java语言开发&#xff0c;建立在开源搜索…

cssip 第11章 : 安全网络架构和保护网络组件

11.1 OSI模型 协议&#xff1a;定义数据如何通过网络介质传输。 11.1.1 OSI模型的历史 开发 OSI 协议是为给所有计算机系统建立通用的通信结构或标准。 OSI模型表示&#xff1a;应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。 11.1.3 封装/解…

What does rpm do?

RPM 是 Red Hat Package Manager 的缩写&#xff0c;顾名思义是Red Hat 贡献出来的软件包管理工具&#xff0c;支持安装、更新、卸载、查询、验证和管理系统软件包。hheg [Ref] linux下的rpm是什么意思 [Ref] 20 个常用的 RPM 命令 RPM 将所有已安装软件包的信息 保存在 /v…

1944. 队列中可以看到的人数

1944. 队列中可以看到的人数 - 力扣&#xff08;LeetCode&#xff09; 1、一个人能看到的人要么比他自己高&#xff0c;要么比他自己矮 2、一个人最多只能看到一个比自己高的人 那可以倒序遍历height 数组&#xff0c;单调栈中降序&#xff0c;a若能弹出b说明b左边第一个比b…

「Vue3面试系列」Vue 3.0中Treeshaking特性有哪些?举例说明一下?

文章目录 一、是什么二、如何做Vue2 项目Vue3 项目 三、作用参考文献 一、是什么 Tree shaking 是一种通过清除多余代码方式来优化项目打包体积的技术&#xff0c;专业术语叫 Dead code elimination 简单来讲&#xff0c;就是在保持代码运行结果不变的前提下&#xff0c;去除…

k8s的存储卷(数据卷)

1、存储卷&#xff1a;容器内的目录和宿主机的目录进行挂载 2、容器在系统上的生命周期是短暂的&#xff0c;delete&#xff0c;k8s用控制器创建的pod&#xff0c;delete相当于重启&#xff0c;容器的状态也会恢复到初始状态&#xff0c;一旦回到初始状态&#xff0c;所有的后…

SpringBoot从数据库读取数据数据源配置信息,动态切换数据源

准备多个数据库 首先准备多个数据库&#xff0c;主库smiling-datasource&#xff0c;其它库test1、test2、test3 接下来&#xff0c;我们在主库smiling-datasource中&#xff0c;创建表databasesource&#xff0c;用于存储多数据源相关信息。表结构设计如下 创建好表之后&#…

平面光波导_三层均匀平面光波导_射线分析法

平面光波导_三层均匀平面光波导_射线分析法 三层均匀平面光波导&#xff1a; 折射率沿 x x x 方向有变化&#xff0c;沿 y y y、 z z z 方向没有变化三层&#xff1a;芯区( n 1 n_1 n1​) > > > 衬底( n 2 n_2 n2​) ≥ \geq ≥ 包层( n 3 n_3 n3​)包层通常为空…

LLM_InterLM-Demo学习

reference Github: https://github.com/InternLM/tutorial/blob/main/helloworld/hello_world.md 1- 环境配置 之前都是用科学上网在huggingFace进行的模型下载&#xff0c;同时还需要进行一些配置 import os os.environ[CURL_CA_BUNDLE] 在本次的学习中发现可以设置镜像或…

Docker容器进入的4种方式(推荐最后一种)

在使用Docker创建了容器之后&#xff0c;大家比较关心的就是如何进入该容器了&#xff0c;其实进入Docker容器有好几多种方式&#xff0c;这里我们就讲一下常用的几种进入Docker容器的方法。 进入Docker容器比较常见的几种做法如下&#xff1a; 使用docker attach使用SSH使用…

【已解决】C语言实现多线程检索数据

本博文源于笔者正在学习的c语言。学习如何用多线程进行检索数据。这里以检索一个数组的数据为例&#xff0c;给出代码&#xff0c;并分析如何进行线程通信&#xff0c;如果检索到&#xff0c;其余就别检索了。 文章目录 问题来源问题解决方案代码实现效果总结 问题来源 想要用…

这可能是最全面的Java集合面试八股文了

内容摘自我的学习网站&#xff1a;topjavaer.cn 常见的集合有哪些&#xff1f; Java集合类主要由两个接口Collection和Map派生出来的&#xff0c;Collection有三个子接口&#xff1a;List、Set、Queue。 Java集合框架图如下&#xff1a; List代表了有序可重复集合&#xff0c…