本文的阅读基本条件:

  • 具备C/C++基础知识,了解面向对象特征
  • 阅读过《Objective-C 2.0 程序设计(第二版)》、《Objective-C 程序设计 第6版》或相关基础OC书籍

知识要点汇总模式: 提出问题。给出详细解释(Q&A)

PS:会以扩展方式延伸介绍一些知识点

问题列表

Q1. Objective-C特点以及和C++的差别?

Q2. 属性的特点。和实例变量的差别,使用注意事项?

Q3. 类的继承。协议和分类的概念和使用,以及须要注意的问题?

Q1. Objective-C特点以及和C++的差别?

Objective-C特点

Objective-C(OC)是C的超集,基于C语言加入了面向对象特性和消息转发机制的动态语言(继承了smalltalk语言面向对象的经典思想)。

除编译器外还须要用执行时(runtime)系统来动态创建类和对象进行消息发送和转发,而runtime系统是一个用C语言编写动态链接库(libobjc.A.dylib)。 该库提供了OC语言所需的各种动态特性的支持。

OC採用消息传递(Messaging)即向对象传递消息的方式而非方法调用。如: [receiver message],编译器并不立即执行对象的message方法,而是向receiver对象发送一条message消息,编译器将其转化为 obj_msgSend (runtime和对象模型详细实现參见Foundation框架要点归纳)及其相关函数调用,在程序执行时会依据obj_msgSend 查找详细方法实现。

简单的说,即OC程序在编译时并未详细确定方法实现,而是在执行时借助runtime系统实现方法的动态绑定,通过obj_msgSend实现查找方法的类别。进而调用方法实现,通过runtime系统实现面向对象的多态特性(不同的类有同样的方法名)。

C++ 和 OC的差别

C++ 也是一种对C实现面向对象特性的扩展,能够从面向对象的三个特性(封装、继承/派生、多态)角度简单分析C++和OC的不同

封装: OC和C++都有自己风格的类结构语法定义方式。OC成员变量默觉得protected。属性是OC的一个特性,用于封装对象中的数据。C++默觉得private。 OC能够通过分类对原始类进行扩充,在不破坏类封装特性的基础上对类进行方法加入,但不能添加成员变量(属性能够)。

继承: C++能够多继承。即同一时候继承多个父类。 OC仅仅能单继承,但通过协议有效添加了继承的灵活性和多样性,弥补了单继承的缺点。

多态: 即同样类具有同名函数(方法)。但能够通过类别来区分实现相应的函数(方法)。C++和OC不同的是其对象採用函数调用方式,且在编译阶段实现类和函数的绑定(虚函数的动态绑定机制除外),这点和OC具有明显的差别,OC是在执行时通过runtime系统来查找详细类别方法并实现。

并且,C++能够实现函数重载功能,OC没有该功能。

Q2. 属性的特点,和实例变量的差别,使用要点?

属性的特点

属性(property)是OC一个特性,用于封装对象中的数据。OC通过定义实例变量来存储对象所需的数据。并通过存取方法(access method。setter,getter)来訪问。

上述概念的成型且经由“属性”这一特性而成为OC 2.0 一部分。

使用“属性”代替定义传统的实例变量和存取方法让编译器自己主动合成存取方法有利于提高程序性能(能够通过@dynamic关键字告诉编译器不要实现属性所用的实例变量和存取方法)。而引入了点语法(dot syntax)更提高程序可读性(”.”语法实际上编译成消息传递模型[receiver message])。

属性关键字(特质)

property有一些具有特殊用途的关键字(特质),一般分为三类:原子性。存取器控制,内存管理

(1)原子性

atomic(默认):仅仅同意一个线程訪问实例变量。线程安全效率低下

nonatomic: 能够被多线程訪问,效率高

(2) 读写权限

readwrite(默认):当属性通过@synthesize实现时,编译器自己主动生成setter和getter方法

readonly :仅仅有属性由@synthesize实现时,编译器才会合成获取方法,仅仅有 getter没有setter

(3)内存管理

显示内存管理策略

assign(默认):用于值类型,如 int,float,NSInteger 等表示单纯的复制

retain: 在setter方法中。须要对传入对象进行引用计数+1的操作,即对对象具有全部权,该对象不会被释放

strong:和retain意思同样。并产生同样代码,但语意上更能体现对象拥有

weak:setter方法中对传入对象不进行引用计数+1的操作,即对传入的对象没有全部权。当对象引用计数为0时,对象被释放,声明实例变量指向nil

unsafe_unretained: 和assign同样,可是它适用于“对象类型”,非拥有关系,当目标对象被清除时,该属性之不被清空(nil, 和weak有差别), 訪问会造成崩溃。

copy: 和strong相似。但差别在于对对象副本拥有全部权而非对象本身。经常使用于NS String * 类型。用于保护其封装性。

property使用要点

  1. 在implementation中假设不用@synthesize, 则使用属性时能够通过 _name(编译器隐藏了 @synthesize name = _name;) 或者self.name , [self name]訪问,点运算符和调用默认getter方法效果一样。
  2. 但假设自己定义了getter或者setter方法,则在方法实现中不能够使用 self ,须要用_name对实例变量进行訪问。否则 会进入死循环, 以下的Demo代码中有体现
  3. 假设使用@synthesize,则能够直接使用变量 name

浅复制(浅拷贝)和深复制(深拷贝)

概念解释:

浅复制: 对于对象中的每一层(对象成员中包括的对象)复制都是指针复制(引用计数角度,每层对象引用计数+1)

深复制:至少有一个对象复制是对象内容复制从引用计数角度出发,除了原对象,其它指针复制的对象引用计数都+1)

方法关联:

retain:始终採取浅复制。引用计数+1

copy: 对于不可变对象,copy 採用的是浅复制。引用计数+1(编译器进行的优化)

对于可变对象copy採用的是深复制,引用计数器不变

mutableCopy: 可变和不可变对象都採用深复制

属性修饰词关联:

retain , strong 都是对象引用计数+1

copy 是拷贝对象副本,引用计数+1

对于常量类型 assign

NSString类 copy

id对象 strong

关联对象 weak

非系统内存管理 unsafed_retained

// ------AClass.h------
#import <Foundation/Foundation.h>
@interface AClass : NSObject
// property
@property (nonatomic, strong) NSString *aName;
// print
- (void)print;
// self-defined getter & setter
// 主要和 自己定义getter方法作比較。通过获取的限制条件
- (NSString *)aName;
@end // ------AClass.m------
@implementation AClass //@synthesize aName = _aName; // 系统隐藏
//@synthesize aName; // print
- (void)print
{
// 调用实例变量
NSLog(@"内部Print方法直接调用实例变量%@", _aName);
// 调用自己定义getter函数
NSLog(@"内部Print方法通过存取方法获取属性%@", self.aName);
NSLog(@"内部Print方法通过存取方法获取属性%@", [self aName]);
} // getter
- (NSString *)aName
{
if ([_aName isEqualToString:@"King"]) { // self.aName 会进入死循环
return _aName;
}
else {
return @"Not King~";
}
}
@end // ------main.m------
int main(int argc, char const *argv[])
{
@autoreleasepool {
AClass *a = [[AClass alloc] init];
a.aName = @"King";
NSLog(@"通过点运算符实现属性訪问: %@", a.aName);
// 调用存取方法的setter
[a setAName:@"King2"];
NSLog(@"通过存取方法实现属性訪问: %@", [a aName]);
NSLog(@"----------------------------------------");
[a print];
return 0;
}
}
OutPut:
通过点运算符实现属性訪问: King
通过存取方法实现属性訪问: Not King~
----------------------------------------
内部Print方法直接调用实例变量King2
内部Print方法通过存取方法获取属性Not King~
内部Print方法通过存取方法获取属性Not King~`

Q3. 类的继承,协议和分类的概念和使用。以及须要注意的问题?

知识点汇总

(Maybe you need it or learn something important)

  • 继承] OC是面向对象语言,继承方式和C++有明显差别即单继承,而没有C++的多继承。但多协议弥补了不能多继承的缺陷。能够通过子类继承的方式

    a.添加新的方法/或实例变量,

    b.类的特别接口封装。

    c. 覆写 一个或者多个方法改变类的默认行为

  • [多态,动态类型和动态绑定]

    多态: 不同的类对象定义同样名称

    动态类型id类型: 直到执行时才确定所属对象的类,通用对象类型,定义为:

    typedef struct objc_object *id;

    (id 变量不能使用点运算符)

    动态绑定:执行时才确定实际要调用的对象方法

  • [分类 - Category]

    提供一种简单方式将类定义模块化到相关方法的组或分类中。一般。假设主类为B,则分类头文件和实现文件名分别为:B+subClass.h, B+subClass.m

    从调用角度,分类就是对原始类的一种扩展

    从程序角度。分类可读性更强

分类文件格式

#import “SuperClassName.h”

@interface Fraction (MathOp)

@end

类扩展

假设创建一种未命名的分类。则称为类的扩展,在有命名的分类中时不同意的。和有命名分类不同,未命名分类主要在主实现区实现,而非分离实现区域。未命名分类扩展的方法和属性或者实例变量仅仅能由该类本身私有。

Category 使用场景:

a. 已经定义的类须要加入新的方法功能

b. 一个类中包括很多种不同类型方法,须要不同团队实现,有利于任务分配

注意问题:

a. Category能够訪问原始类方法。但不能加入变量,加入变量能够通过创建子类(继承)方式来实现

b. Category能够重载原始方法,会导致不能訪问原来的方法,创建子类实现 重载 覆写

c. 和普通接口有所差别,分类实现文件里能够不必实现全部声明的方法

  • [协议]

    协议 即多个类共享一个方法列表,协议中列出的方法没有相应的实现,通过文档说明,使用协议中的方法能够通过文档说明进行实现。

一系列不属于不论什么类的方法列表,当中声明的方法能够被不论什么类实现。

这样的模式称为代理模式。

在不同场景中实现不同模式。Apple採用了大量的代理模式来实现 MVC中 View和 Controller 的解耦。

最经常使用的是托付代理模式。 Cocoa框架中大量採用这样的模式实现 数据和UI的分离: UIView产生的全部事件 都是通过托付的方式 交给 Controller 完毕

框架中后缀为Delegate都是 Protocol

@protocol NSCopying

- (id)copyWithZone:(NSZone *)zone;

@end

(能够放在单独的.h头文件里定义。也能够放在相关类的h文件里)

使用:

@interface AddressBook : NSObject< NSCopying, NSCoding >

PS:

  1. 不是必需在接口部分声明协议的方法。但要在实现部分定义这些方法

    2. 能够通过 例如以下代码来检查一个对象是否遵循某项协议

    id currentObject;

    if ([currentObject conformsToProtocol:@protocol(Drawing)] == YES) {

    }

    3. 也能够使用 respondsToSelector:@selector() 来检查是否实现了可选的方法

    代理(delegation)

    -(BOOL)respondsToSelector:selector 被广泛用于实现托付方法定义

    4. id currentObject; 借助编译器来检查变量一致性

    5. 和类名一样,协议名必须唯一

    6. 协议是能够继承的,具有继承的属性。假设协议B继承了协议A,则实现协议B 须要实现A和B的全部方法

    • [代理] delegation

      协议是一种两个类之间的接口定义,定义了协议的类能够看作是将协议定义的方法代理给实现他们的类。

      (定义了协议的类称为 代理)

測试程序

//******測试样例: (涵盖之前一些内容,算是整合一下思路)
//******MTProtocol.h 文件,为定义的协议
@protocol Printing
// 默认
@required
- (void)printProtocol;
@optional
- (void)printProtocolOptional;
@end //******A.h 文件,包括A类定义。採用Printing协议
#import <Foundation/Foundation.h>
#import "MTProtocol.h"
// 接口处定义实例变量, 採用协议
@interface A : NSObject <Printing>
{
int x;
}
@property (nonatomic, assign) int y;
- (void)initXY;
- (void)printXY;
@end //******A.m 文件,包括A类实现,注意实例变量和属性初始化的问题(这里没有重载init方法,所以不须要模版 self = [super init] 。。。)
#import "A.h"
@implementation A
- (void)initXY
{
x = 1;
self.y = 2;
}
- (void)printXY
{
NSLog(@"This is Class A : %i, %i", x, self.y);
}
- (void)printProtocol
{
NSLog(@"I am printProtocol Method form Printing!");
}
- (void)printProtocolOptional
{
NSLog(@"I am printProtocolOptional Method form Printing!");
}
@end //******A+Op.h A类的分类接口,用于扩展(感觉就是扩展。一方面通过子类。一方面在原类中进行分类扩展,或者 合成类 这个比較奇葩)
#import "A.h"
@interface A (Op)
- (void)printCategory;
@end //******A+Op.m A类的分类实现
#import "A+Op.h"
@implementation A (Op)
- (void)printCategory
{
NSLog(@"Op Category for Class A!");
}
@end //******B.h B类接口,A 类子类。在B类中我们尝试 未命名分类,即私有方法扩展
#import "A.h"
@interface B : A
- (void)initXY;
- (void)printXY;
@end //******B.m B类实现,注意未命名分类
#import "B.h"
@interface B ()
- (void)printNanNameCategory;
@end
@implementation B
- (void)initXY
{
x = 10; // A类中接口处定义了实例变量,能够被继承
super.y = 20; // 属性或者实现部分声明的变量为私有实例变量。通过合成取值方法获取
}
- (void)printXY
{
NSLog(@"This is Class B : %i, %i", x, self.y);
}
- (void)printNanNameCategory
{
NSLog(@"I am Nan Name Category for B!");
}
@end //******main.m 实现,注意未命名分类
#import "A+Op.h"
#import "B.h"
// ---------- main ---------- int main(int argc, const char * argv[]) {
@autoreleasepool {
A *a = [[A alloc] init];
B *b = [[B alloc] init]; [a initXY];
[b initXY];
// 定义动态类型 id
id tmp = a;
[tmp printXY];
[tmp printCategory];
[tmp printProtocol];
[tmp printProtocolOptional]; tmp = b;
[tmp printXY]; [tmp printProtocolOptional]; // 測试 tmp 是否是A类别
//[tmp isKindOfClass:[A class]] ? NSLog(@"Yes") : NSLog(@"No");
// 測试A 类是否包括printXY方法
//[A instancesRespondToSelector:@selector(printXY)] ? NSLog(@"Yes") : NSLog(@"No");
// 測试对象a 是否包括init方法
//[a respondsToSelector:@selector(init)] ? NSLog(@"Yes") : NSLog(@"No");
}
}

结果分析

This is Class A : 1, 2

Op Category for Class A!

I am printProtocol Method form Printing!

I am printProtocolOptional Method form Printing!

This is Class B : 10, 20

I am printProtocolOptional Method form Printing!

參考资源

Objective-C 2.0 基础要点归纳的更多相关文章

  1. Swif语法基础 要点归纳(一)

    常量和变量 用let声明常量      let m = 20 用var声明变量      var n = 0 类型推导机制           声明常量或变量时.能够不指定常量/变量类型,编译器会依据 ...

  2. HTML基础要点归纳

    一.开发环境 常用的HTML编辑器有Sublime Text.Hbuild.Dreamweare.以及vs code.pycharm等都可以.我目前在用的就是Sublime text3和Hbuild两 ...

  3. Android程序开发0基础教程(一)

    程序猿学英语就上视觉英语网 Android程序开发0基础教程(一)   平台简单介绍   令人激动的Google手机操作系统平台-Android在2007年11月13日正式公布了,这是一个开放源码的操 ...

  4. 0基础搭建Hadoop大数据处理-编程

    Hadoop的编程可以是在Linux环境或Winows环境中,在此以Windows环境为示例,以Eclipse工具为主(也可以用IDEA).网上也有很多开发的文章,在此也参考他们的内容只作简单的介绍和 ...

  5. Python 0基础开发游戏:打地鼠(详细教程)VS code版本

    如果你没有任何编程经验,而且想尝试一下学习编程开发,这个系列教程一定适合你,它将带你学习最基本的Python语法,并让你掌握小游戏的开发技巧.你所需要的,就是付出一些时间和耐心来尝试这些代码和操作. ...

  6. 手把手0基础项目实战(一)——教你搭建一套可自动化构建的微服务框架(SpringBoot+Dubbo+Docker+Jenkins)...

    原文:手把手0基础项目实战(一)--教你搭建一套可自动化构建的微服务框架(SpringBoot+Dubbo+Docker+Jenkins)... 本文你将学到什么? 本文将以原理+实战的方式,首先对& ...

  7. CORS基础要点:关于dataType、contentType、withCredentials

    事实上,面试时我喜欢问跨域,因为多数开发者都知道它并且常用,而我希望能从面试者的回答中知道他在这个问题的深入程度,进一步看看面试者研究问题的思维方式及钻研精神,然而确实难到了很多人,当然这也不是面试通 ...

  8. <-0基础学python.第一课->

    初衷:我电脑里面的歌曲很久没换了,我想听一下新的歌曲,把他们下载下来听,比如某个榜单的,但是一首一首的点击下载另存为真的很恶心 所以我想有没有办法通过程序的方式来实现,结果还真的有,而且网上已经有有人 ...

  9. Android 工程在4.0基础上混淆

    Android现在对安全方面要求比较高了,我今天要做的对apk进行混淆,用所有的第三方工具都不能反编译,作者的知识产权得到保障了,是不是碉堡了. 一,首先说明我这是在4.0基础上进行的. 先看看pro ...

随机推荐

  1. bootstrap 整理

    form-control   输入框,独占一行,占满. form-group  增加下边距 <label> 字体会加粗,不是独占一行 .col-xs-  超小屏 .col-sm- 平板 . ...

  2. C#面试问题及答案

    1.遇到高并发的问题如何解决? 优化SQL语句 多线程 分布式服务器 集群 拆表2.Dictionary和ConurrentDictionary的区别? 后者是线程安全的 前者适用于单线程3.Dict ...

  3. ubuntu 18.04 安装.net core

    要求某些软件包保持现状,就是它们破坏了软件包间的依赖关系那就只好在琢磨了,然后就发现了在github有安装的方法因为是18.04 所以 wget -qO- https://packages.micro ...

  4. java上传文件大小转换(字节转kb/mb/gb)

    /** * 字节转kb/mb/gb * @param size * @return */ public String getPrintSize(long size) { //如果字节数少于1024,则 ...

  5. Unexpected token d in JSON at position 669 while parsing near '...ct-mode":"^6.0.2"}

    问题 在安装 babel 的时候,遇到问题 Unexpected token d in JSON at position 669 while parsing near '...ct-mode" ...

  6. Java中9大内置基本数据类型Class实例和数组的Class实例(转载)

    https://www.jianshu.com/p/58976c8bf1e1

  7. Java中的日期、时间操作

    每次在处理日期时间的时候都要打开chrome查找一番,索性自己找一下满意的记录下来. 一.时间格式 // hh表示12小时制: HH表示24小时制 SimpleDateFormat format1 = ...

  8. 版本控制git之五-标签管理 tags 标签 代码版本 如: v1.0

      版本控制git之五-标签管理 打标签 像其他版本控制系统(VCS)一样,Git 可以给历史中的某一个提交打上标签,以示重要. 比较有代表性的是人们会使用这个功能来标记发布结点(v1.0 等等). ...

  9. Why Countries Succeed and Fail Economically

    Countries Succeed and Fail Economically(第一部分)" title="Why Countries Succeed and Fail Econo ...

  10. 【HDU 2196】 Computer (树形DP)

    [HDU 2196] Computer 题链http://acm.hdu.edu.cn/showproblem.php?pid=2196 刘汝佳<算法竞赛入门经典>P282页留下了这个问题 ...