【Effective_Objective-C_1熟悉Objective_C】

news2025/1/11 4:09:19

文章目录

  • 说在前面的
  • 熟悉ObjectiveC
    • first了解Objective-C的起源
          • 1.消息结构和函数调用
          • 运行期组件
          • 内存管理
          • Objective-C的起源要点总结
    • Second 在类的头文件尽量少饮入其他文件
        • 尽量延后引入头文件或者单独开辟一个文件
        • 向前声明
        • 在类的头文件尽量少饮入其他文件要点总结
    • THIRD-多用字面量语法,少用与之等价的方法
      • 字面量语法
        • 字面量语法NSNumber
        • 字面量数组
        • 字面量语法的抛出异常
        • 字面量更安全
        • 字面量字典
        • 字面量字典的抛出异常
        • 可变数组和字典的修改
        • 字面语法的局限性
        • 字面量语法要点总结
    • Fourth - 多用类型常量,少用#define预处理命令
        • 定义常量的命名
        • 定义常量的位置方法
        • static const的好处
  • 问题记录
        • 想定义一个全局常量的做法
  • 问题2
        • 多用类型常量,少用#define预处理命令总结要点
    • 用枚举表示状态选项选项码

说在前面的

  • 从Effective_ObjectiveC这本书开始,进入对ObjectiveC的全新学习,如何编写高质量的ObjectiveC代码及如何了解这门语言的内部结构。
  • 这里写一下看了第一章之后的总结和理解
  • 虽然开始看的迷迷糊糊,不过也是一种对基础的复习

熟悉ObjectiveC

  • ObjectiveC是通过一套全新的语法,在C的基础上添加了面向对象的特性,第一章简单的讲解了基础知识

first了解Objective-C的起源

1.消息结构和函数调用
  • 和C++,Java一样,Objective-C也是面向对象语言,但是它们在许多方面都有差别。差别在于Objective-C使用的是消息结构而非函数调用,Objective-C语言由Smalltalk1演化而来的,Smalltalk是消息型语言的鼻祖
  • 消息和函数调用的区别,小🌰例子
//Messaging(Objevtive-C)
Object *obj = [Object new];
[obj performWith:parameter1 and:parameter2];

//Function calling(C++)
Object *obj = new Object;
obj->perform(parameter1, parameter2);

    • 消息结构和函数调用的关键差别在于:使用消息结构的语言,其运行所应执行的代码由运行环境来决定;而使用函数调用的语言,则由编译器决定
    • 对于函数结构,如果范例代码的调用函数是多态的,那么就在运行时按照虚方法表来查出来到底执行哪个函数,而采用消息结构的语言,不管是否为多态总是在运行时才回去查找所要执行的方法。
运行期组件
  • 对于Objective-C的主要工作都由运行期组件(runtime component)而非编译器完成✅
  • 运行期组件本质上是一种与开发者所编写代码相链接的动态库,其代码能够把开发者编写的所有程序粘合起来,这样的话要提升性能即更新运行期组件即可
内存管理
  • Objective-C是C的“超集”(superset),所以C语言中的所有功能在编写Objective-C代码时依然适用。所以要想写出高效的OC代码就得完全掌握OC和C这两门语言,其中尤为重要的是要理解C语言的内存模型(memory medel),这有助于我们理解OC的内存模型和“引用计数”(reference counting)机制的工作原理
    请添加图片描述
  • 例如上述代码,声明了一个someString 的变量,此变量为指向NSString的指针,因为OC声明变量基本上都为指针变量,所以OC对象所占内存总是分配在“堆空间”(heap space)中,而绝不会分配在“栈”(stack)上
  • 如果再次创建一个对象Same,那么这两个对象队徽分配在堆中,它们同时指向了堆中的NSSt ring实例
    请添加图片描述
  • 对象分配在栈上,而实例分配在堆中
  • 分配在堆中的内存必须直接管理,而分配在栈上用于保存变量的内存则会在其栈帧弹出时自动清理。
    • 但是Objective-C将堆内存管理抽象成了引用计数
Objective-C的起源要点总结
  • Objective-C为C语言添加了面向对象特性,是其超集。Objective-C使用动态绑定的消息结构,也就是说,在运行时才会检查对象类型。接收一条消息之后,究竟应执行何种代码,由运行期环境而非编译器来决定。
  • 理解C语言的核心概念有助于写好Objective-C程序。尤其是要掌握内存模型和指针。

Second 在类的头文件尽量少饮入其他文件

  • Objective-C采用的是头文件和实例文件区分代码,头文件.h ,实例文件.m,这里以EOCPerson为例格式如下
    • EOCPerson.h
      请添加图片描述
    • EOCPerson.m
      请添加图片描述
  • 对于在EOCPerson里想添加一个新类EOCEmployer,然后去调用EOCEmployer的属性,通常会这样做
    请添加图片描述
  • 然后在EOCPerson的h文件里面添加#import "EOCEmployer.h"文件,你的代码就是这样子的
    请添加图片描述
  • 我们知道在h文件里面是不需要调用EOCEmployer的属性的,也就是编译器不需要知道EOCEmployer的全部细节,只需要有一个EOCEmployer类即可,幸好-向前声明完成了这个要求
  • 向前声明该类,@class + 类,你的头文件变成了这样
    请添加图片描述
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class EOCEmployer;
@interface EOCPerson : NSObject
@property (nonatomic, copy)NSString *eocName;
@property (nonatomic, copy)NSString *eocAge;
@property (nonatomic, strong)EOCEmployer *employer;
@end

NS_ASSUME_NONNULL_END
  • 而当你需要实现EOCEmployer接口的全部细节时候只需要在实现文件里添加#import "EOCEmployer.h"即可
#import "EOCPerson.h"
#import "EOCEmployer.h"

@implementation EOCPerson

@end

尽量延后引入头文件或者单独开辟一个文件

  • 将引入头文件的时机尽量延后,只在需要的时候才引入,这当然会减少编译时间,提升效率
  • 有时候必须要在头文件引入其他头文件,例如遵守某个协议并且必须实现全部细节,这个时候我们可以把该协议单独写一个文件避免了不必要的编译会延期编译效率

向前声明

  • 解决了这两个类相互引用问题
  • 相互引用:有两个类,它们都在头文件中引入了对方的头文件,两个类都进行各自的引用解析,这样就会导致“循环引用”(chicken-and-egg situation)。虽然我们使用#import而非#include不会导致死循环,但是这意味着两个类中有一个类无法被正确编译。
  • 但是,有时候就必须引入头文件,比如继承以及遵循的协议

在类的头文件尽量少饮入其他文件要点总结

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

THIRD-多用字面量语法,少用与之等价的方法

  • 之前学习疯狂iOS讲义的时候了解过Foundatiob框架,其中包含了NSString,NSNumber,NSarray,NSDictionary类

字面量语法

  • 简单的说就是直接给字符串等变量赋值而不是采用系统方法,这是在Objective-C1.0之后就被允许的

字面量语法NSNumber

  • 系统的方法
NSNumber *number = [NSNumber numberWithInt:19];
  • 字面量语法
    NSNumber *number = @19;
  • 字面量明显相对于系统方法更加的简洁化,以字面量表示🌿数值方法十分有用,可以使NSNumber对象更加简洁。声明里只包含了数值,并无多余成分

字面量数组

  • 创建数组和取数组元素都会更加简洁请添加图片描述
 NSArray* array = [NSArray arrayWithObjects:@"1", @"2", @"3", @"4", nil];
    NSString* stringOne = [array objectAtIndex:0];
    NSLog(@"%@", stringOne);
    NSArray* antherArray = @[@"1", @"2", @"3", @"4"];
    NSString* stringone = antherArray[0];
    NSLog(@"%@", stringone);

字面量语法的抛出异常

  • 用字面量创建数组时要注意,若数组元素对象中有nil,则会抛出异常,因为字面量语法实际上是一种“语法糖”(syntactic sugar),其效果相当于是先创建了一个数组,然后把方括号里的所有对象都添加到这个数组中。
  • 例如请添加图片描述
    请添加图片描述
  • 使用arrayWithObjects方法试试
 id obj1 = @"1";
    id obj2 = nil;
    id obj3 = @"3";
    NSArray* array = [NSArray arrayWithObjects:obj1,obj2, obj3, nil];
    NSLog(@"%@", array);![请添加图片描述](https://img-blog.csdnimg.cn/bd84d7c9a4d74328a0880b6d834216c9.png)

请添加图片描述

  • 通过打印结果可以知道对于arrayWithObjects方法系统会依次处理各个参数知道出现nil为止,也就是第二个元素为nil 系统提前结束了数组的创建。

字面量更安全

  • 通过对比可以知道字面量语法会自动抛出异常终止了程序的进行和不必要的错误,我们可以通过异常更快的发现错误

字面量字典

  • 系统的 dictionaryWithObjectsAndKeys方法是这样的初始化
//字面量字典
    NSDictionary *personDict = [NSDictionary dictionaryWithObjectsAndKeys:@"lyt", @"name", @"mh", @"love", [NSNumber numberWithInt:644], @"day", nil];
   
    • 系统的 dictionaryWithObjectsAndKeys方法的value key的格式显得不是很人性化,对于一个day,还不能直接放进去,需要利用NSNumber封装
//字面量字典
    // 字面量更人性化
    NSDictionary* personData = @{@"name": @"lyt", @"love":@"mh", @"day":@644};
  • 字面量语法对比系统的语法看着更简明,其中还有分割每一组对象,理解起来更加顺畅,而且对于数字直接加一个@即可

字面量字典的抛出异常

  • 和数组一样在这里不过多赘述,也是帮助我们及时发现错误!

可变数组和字典的修改

  • 如果数组和对象是可变的,那么也可以通过简单的字面量语法下标修改其中的值
  • 两种方法的对比
mutableArray[1] = @"l y t t t";
mutableDictionary[@"day"] = @"645";

字面语法的局限性

  • 除了字符串以外,所创建出来的对象必须属于Foundation框架才行。如果自定义了这些类的子类,则无法用字面量语法创建其对象
  • 使用字面量语法创建出来的字符串数组和字典都是不可变的,变成可变的对象需要手动复制方法,再创建一个可变对象.
    • 字面量语法初始化可变对象会警告
      请添加图片描述
    • 当调用的时候会抛出异常,我试着改变里面的内容
 NSMutableArray* array = @[@"1", @"2"];
    [array replaceObjectAtIndex:1 withObject:@"20"];

请添加图片描述

 NSArray* antherArray = @[@"1", @"2", @"3", @"4"];
    NSMutableArray* mutableArray = [antherArray mutableCopy];
//    [mutableArray replaceObjectAtIndex:1 withObject:@"20"];
    mutableArray[1] = @"20";
    NSLog(@"%@", mutableArray[1]);

请添加图片描述

  • 把字面量语法的对象手动变成可变对象虽然要多调用一个方法和创建一个对象,但是利大于弊

字面量语法要点总结

  • 应该使用字面量语法来创建字符串、数值、字典。与创建此类对象的常规方法相比,这么做更加简明扼要。
  • 应该通过取下标操作来访问数组下标或者字典中的键对应的元素
  • 用字面量语法创建数组或者字典时,若值中有nil,则会抛出异常。因此,务必确保值里不含nil。
  • 字面量创建字典数组字符串都是不可变的,需要自己再调用一个方法和创建一个可变的对象来避免出现异常

Fourth - 多用类型常量,少用#define预处理命令

  • 这个看的不是很懂,简单的记录一下重点内容
  • 编写代码的时候需要定义常量,在C语言里学过#define预处理

定义常量的命名

#define kString iOS
  • 在实际的开发里面,这样定义出来的常量没有类型信息,并且假设此命令在某个头文件中,那么所有引入了这个头文件的的代码,其定义的固定值都会被这个替换掉,很槽糕!
  • 在树上提供了这样的定义方法
static const NSString* kString = @"iOS";

请添加图片描述

  • 这种方式定义的常量包含类型信息,其好处是清楚的描述了常量的含义,可以看出这个一个NSString* 类型的变量

定义常量的位置方法

  • 定义常量的位置是极其重要的,我们总喜欢在头文件里声明预处理指令,那么引入了这个头文件的所有文件都会含有这个变量,万一重名,程序变得异常麻烦
  • 所以最好不要在头文件中定义常量,不论你是如何定义常量的,因为OC中没有“名称空间”这一概念

static const的好处

  • 不打算公开某个常量,就应该将其定义在使用该常量的实现文件里面,并且变量要用 static const 一起声明。
  • 关于static:使用static意味着该变量仅在定义的文件里面可见,达到了保护变量的作用,这里还涉及到了static关键字,之前有学习过深入理解static关键字
  • 关于const:对于上述static const的字符串,如果仅用const修饰则编译器会为他创建一个外部符号,此时若另一个编译单元也声明了同名变量,那么编译器就会抛出错误信息,这个建议我还没有实现!

问题记录

  • 对于上述说明实际上我测试了一下并没有报错,暂时作为待解决的问题之一吧?

想定义一个全局常量的做法

  • 有时候我们需要对外公开我们的常量,比如说是通知时的通知名称,我们定义一个常量,外界就可以直接使用这个常值变量来注册自己想要接收的通知即可,而不用知道实际字符串的值。此类常量需放在“全局符号表”中,以便可以在定义该常量的编译单元之外使用
  • 定义使用extern关键字
    • 在头文件请添加图片描述
    • 在实现文件、请添加图片描述
  • 注意⚠️:extern就是告诉编译器,在全局符号表中将会有一个名叫EOCStringConstant的符号,也就是说,编译器无需查看其定义。
  • 此常量必须定义而且只允许被定义一次,通常定义在头文件对应的实现文件里面

问题2

  • 我对上面定义的常量进行了一次extren关键字定义,然后在多个文件里面的h文件按照extren关键字也定义了一样的名字类型却没有报错?很疑惑??????

多用类型常量,少用#define预处理命令总结要点

  • 不能用预处理指令定义常量。这样定义出来的常量不含类型信息,编译器只是会在编译前据此执行查找与替换操作。即使有人重新定义了常量值,编译器也不会产生警告信息,这将导致应用程序中的常量值不一致。
  • 在实现文件中使用static const来定义“只在编译单元内可见的常量”。由于此常量不在全局符号表中,所以无需为其名称加前缀。
  • 在头文件中使用extern来声明全局变量,并在相关实现文件中定义其值。这种常量要出现在全局符号表中,所以其名称应该加以区隔,通常用与之相关的类名做前缀。
  • 我觉得主要注意的点是static const关键字的使用,保留私有化,仅在当前文件调用,保证了安全性

用枚举表示状态选项选项码

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

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

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

相关文章

梯度下降法的理解

1 梯度下降法 本文所有的数学定义概念非官方所给&#xff0c;皆来自于个人理解融合 1.1 梯度的定义 个人理解就是能够使函数值增大最快的方向 需要明确的一点&#xff0c;这里说的方向都是自变量变化的方向 1.2 梯度下降法 梯度下降法本质上是用来求解目标函数最小值的一种…

CocosCreater学习1

1.产品定位 Cocos Creator 是以内容创作为核心&#xff0c;实现了脚本化、组件化和数据驱动的游戏开发工具。具备了易于上手的内容生产工作流&#xff0c;以及功能强大的开发者工具套件&#xff0c;可用于实现游戏逻辑和高性能游戏效果。 2.工作流程 3.项目文件夹结构 初次创…

C++入门基础01:指针与引用

C入门基础&#xff1a;指针与引用 指针 #include <iostream> //系统定义头文件一般是尖括号 #include<fstream> #include<string> using namespace std;//引用与指针 //是复合数据类型&#xff0c;与基本数据类型int、double这类是不一样的 //指针存储的是…

Java集合框架详解(一)Collection接口、List接口、ArrayList类、Vector类

一、集合架构图 二、Collection接口 Collection集合的遍历 迭代器&#xff1a;Iterater 方法名称备注Iterater Iterater()返回在此collection的元素上进行迭代的迭代器boolean hasNext()如果有元素可以迭代&#xff0c;返回true&#xff0c;否则返回falseE next()返回迭代的下…

Kafka - Kafka生产者|发送消息|分区策略|提高吞吐量|数据可靠性|数据去重|数据有序

文章目录1. Kafka 生产者2. 生产者发送消息1. 生产者异步发送消息2. 生产者异步发送消息带回调函数3. 生产者同步发送消息3. 生产者发送消息的分区策略1. Kafka 分区好处2. 分区器 DefaultPartitioner 和 ProducerRecord 源码3. 指定 partition 的情况4. 没有指定 partition 但…

从零集成mybatis-plus

Mybatis-Plus特性&#xff1a; 无侵入&#xff0c;即引入它不会对现有工程产生影响。损耗小&#xff0c;启动就会自动注入基本的CRUD&#xff0c;内置通用Mapper、Service等&#xff0c;基本能满足大部分需求。支持主键自动生成&#xff0c;其中包括分布式唯一ID生成器Sequenc…

PTA题目 分段计算居民水费

为鼓励居民节约用水&#xff0c;自来水公司采取按用水量阶梯式计价的办法&#xff0c;居民应交水费y&#xff08;元&#xff09;与月用水量x&#xff08;吨&#xff09;相关&#xff1a;当x不超过15吨时&#xff0c;y4x/3&#xff1b;超过后&#xff0c;y2.5x−17.5。请编写程序…

[附源码]java毕业设计时事资讯平台

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

黑*头条_第1章_项目介绍和工程搭建

黑*头条_第1章_项目介绍和工程搭建 文章目录黑*头条_第1章_项目介绍和工程搭建学习目标1. 项目介绍1.1项目背景1.2 项目概述1.3 项目术语定义2. 项目需求2.1 APP主要功能大纲2.2 APP用例图&#xff08;主要功能&#xff09;2.3 WEMEDIA功能大纲2.4 WEMEDIA用例图&#xff08;主…

STM32嵌入式工程师自我修养

STM32嵌入式工程师自我修养一、STM32必备技能二、程序员必须熟知三、学习STM32自备资料和硬件一、STM32必备技能 1、熟悉 C 语言编程&#xff0c;熟练 STM32CUBEMX,Keil 开发环境。 2、熟悉基于STM32 MCU开发&#xff0c;掌GPIO,TIME,PWM,ADC等外设开发。 3、熟悉USART,IIC,SP…

快速熟悉C++之常用语法

函数重载&#xff08;Overload&#xff09; 规则 函数名相同 参数个数不同、参数类型不同、参数顺序不同 ◼ 注意 返回值类型与函数重载无关 调用函数时&#xff0c;实参的隐式类型转换可能会产生二义性 ◼ 本质 采用了name mangling或者叫name decoration技术 ✓…

Java锁对象

Java锁 1. 对象头 1.1 简介 以32位的 JVM 为例&#xff0c;每个Java对象的对象头都包含了如下信息 # 组成 Mark Word: 锁的信息&#xff0c;hashcode&#xff0c;垃圾回收器标志 Klass Word: 指针&#xff0c;包含当前对象的Class对象的地址&#xff0c;类对象来确…

基于python的校园社团管理系统的设计与实现

摘 要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&…

JS 类总结

类 class 关键字是 ES6 新增的。类&#xff08;class&#xff09;是ECMAScript 中新的基础性语法糖&#xff0c;本质上还是一个函数&#xff0c;但实际上它使用的仍然是原型和构造函数的概念。并且类受块级作用域限制。 class Person { } console.log(Person);// class Perso…

Java无锁并发

共享资源 1. 不安全场景 package com.nike.erick.d05;import lombok.Getter;import java.util.concurrent.TimeUnit;public class Demo01 {public static void main(String[] args) throws InterruptedException {BankService bankService new BankService();for (int i 0;…

H5 app开启web调试

前言&#xff1a; 在Android app逆向时&#xff0c;H5类型的app的加密通常在js中&#xff0c;所以就需要一种手段来查看源代码&#xff0c;查看加密过程。 0、如何确认h5 app 以狗东为例&#xff1a; 随便选择一个元素&#xff0c;可以看到是控件下的一个类 通过与H5类型的ap…

[附源码]SSM计算机毕业设计在线课程网站JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

基于java_ssm_vue鲜花在线销售商城网站-计算机毕业设计

现在&#xff0c;许多人都喜欢在节日的时候给家人或朋友送鲜花&#xff0c;但是有时候会因为工作忙而忘记或者是没有时间自己去买&#xff0c;同时也有些人觉得自己去买有些麻烦&#xff0c;所以鲜花网络销售是很有必要的。这个网站应该可以提供提前预定、送货上门等服务。首先…

Arduino开发实例-MAX30100传感器模块连接问题解决

MAX30100传感器模块连接问题解决 MAX30100 是一款集成脉搏血氧饱和度和心率监测传感器解决方案。 它结合了两个 LED、一个光电探测器、优化的光学器件和低噪声模拟信号处理,以检测脉搏血氧饱和度和心率信号。 MAX30100 采用 1.8V 和 3.3V 电源供电,可通过软件关断,待机电流…

【Java第33期】:在普通的Maven项目中存储Bean对象并获取和使用

作者&#xff1a;有只小猪飞走啦 博客地址&#xff1a;https://blog.csdn.net/m0_62262008?typeblog 内容&#xff1a;存储Bean对象&#xff0c;再在Spring中获取Bean对象&#xff0c;对其进行使用。 文章目录前言一&#xff0c;存储Bean对象1&#xff0c;创建Bean对象2&…