OC系列教程之对象、属性、类等解析

参考:https://blog.csdn.net/fww330666557/article/details/43232593

一、概述

Object-C是OS

X和iOS上的主要程序开发语言。它是C语言的超集,提供了面向对象和动态运行时(多态,调用都是消息机制进行的)的功能。Object-C继承了C语言的语法、基本类型和流程控制语句,同时添加了定义类和方法的语法。当进行动态类型识别和绑定的时候,Object-C还添加了对象结构管理和对象语法的语言层面的支持,将很多工作延迟到了运行时进行处理。

二、类的声明与实现

Object-C类声明,一般在一个独立的头文件中进行,比如声明一个名称为yourClass的类的一般格式如下:

[objc]

  @Interface yourClass :NSObject  

  …  

  @end  

NSObject是Object-C中所有类的根类,也就是说,所有类要么从它派生,要么从它的子类派生。但你一次只能从一个类派生,因为Object-C是单继承的。

yourClass类的实现一般在yourClass.m文件中,其一般格式为:

[objc]

view plain 

copy

  #import  “yourClass.h“  

  @implementation yourClass  

  …  

  @end  

#import,它类似C语言的#include。只不过,在Object-C中,它比#include更好用,它可以防止重复包含。也就说#inlcude依然可以使用,但#import更好。

三、属性

1、属性的声明与修饰

属性就是对象的数据。属性使用@property关键字声明。一般格式如下:

[objc]

view plain 

copy

  @property NSString *firstName;  

  @property NSString *lastName;  

多个属性之间,可以使用逗号分隔:

[objc]

view plain 

copy

  @property (strong, nonatomic) UIWindow *window;  

属性通常还会加一些修饰,来控制数据的访问和存储等:

[objc]

view plain 

copy

  @property  (readonly)  NSString *firstName;  

  @property  (readonly)  NSString *lastName;  

readonly与readwrite:

readonly表明该属性是只读的,外部不能修改其值。与readonly相对的修饰是readwrite,但你不必把它写出来,因为它是默认的。

atomic与nonatomic:

(atomic、nonatomic)属性用于多线程编程,属性默认是atomic的。在多线程环境下设置为atomic可以保证数据读取的一致性(因为,它将保证数据仅仅被一个线程独占。也就是说一个线程进行写操作时,将锁定该属性,不允许其他的线程进行写操作。)由于该操作会对数据进行锁操作,故会消耗较多的资源。所以在不需要进行多线程操作时建议将该属性设置为nonatomic,设置为该参数时程序在任何情况都不会锁定该属性。

****************************************

引用自:https://blog.csdn.net/sinat_30162391/article/details/50667087

【atomic/nonatomic】 

(1)atomic[默认属性]:OC使用的一种线程保护技术,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。 

(2)nonatomic:非原子性访问,属性赋值的时候不加锁,多线程并发访问会提高性能。但可能会造成不安全。如果不加该属性,则默认setter/getter两个方法都是原子性事务访问。

所以,atomic和nonatomic用来决定编译器生成的getter,setter是否为原子操作。

******************************************

strong与weak:

  其中strong是默认的。strong表示该属性对其相应的对象是强引用。一个变量保持对一个对象的强引用,只要该变量在其作用域范围内或者直到它被赋给另一个对象或者nil为止。weak表示对属性对应的对象的弱引用。

*******************************************

Strong 类似深拷贝,另开辟内存,拷贝对象

Weak 类似浅拷贝,浅拷贝直接引用统一地址

【strong和weak】/

ARC下使用 

(1)strong[默认值]:表明这是一个强引用。相当于retain属性。只要引用存在,对象就不能被销毁。当所有强引用消除时,对象才能被释放。 

(2)weak:弱引用。相当于assign属性。一般为了避免retain

cycles(就是父类中含有子类,父类retain了子类;子类中又调用了父类,子类又retain了父类),导致无法release,才会使用weak。 

小结:(ARC下)你是不能使用retain,release,autorelease这些方法的,因为ARC会在必要的地方自动插入这些语句。所以我们需要在对象属性加上strong或者weak。

*********************************************

copy、assign、retain:

copy修饰表示该属性将使用强引用,因为它必须保持它创建的新对象。

assign指定setter方法用简单的赋值,不更改索引计数(Reference

Counting),一般对简单数据类型 使用assign。

retain,对象引用计数加一。

*******************************************

【assign/copy/retain】 

(1)assign[默认值]:简单赋值,不更改引用计数,不考虑内存管理;常常用于基础数据类型(NSInteger)和C语言数据类型(int

,float,double,char等)。 

(2)copy:建立一个引用计数为1的对象,然后释放原有对象;常常用于NSString/NSArray/NSDictionary(不可变)。在赋值时传入值的一份拷贝,拷贝工作由copy方法执行/block中使用copy。 

(3)retain:

释放旧的对象,将旧对象的值赋给输入对象,再把输入对象的引用计数+1.

;常常用于NSObject和其子类。需要对变量release,再retain新值。指定retain会在赋值时唤醒传入值的retain消息,此属性只能用于OC对象类型,而不能用于Core

Foundation(retain会增加对象的引用计数,而基本数据类型或者Foundation对象都没有引用计数的概念)。 

小结:assign和retain的区别,就是使用引用计数,可以对一个内存的释放方便很多。copy就是把原来的内存复制一遍,使各自都拥有一个内存,这样释放的时候也不会出错。 

【copy和retain的区别】 

copy是创建一个新对象。retain是创建一个指针,引用计数+1. 

如:一个NSString对象,内存地址为:0x1111,内容为@“Hello”。 

(1)copy到另外一个NSString后,地址为0x2222,内容相同(新建一个内容,内容拷贝),新的对象引用计数为1,旧的对象没有改变。 

(2)retain到另外一个NSString后,地址相同(新建一个指针,指针拷贝),内容相同,对象的引用计数+1. 

【assign和retain的区别】 

(1)接触过C,那么假设你用malloc分配了一块内存,并且把它的地址赋值给了指针a,后来你希望指针b也共享这块内存,于是你又把a赋值给(assign)了b。此时a和b指向同一块内存,请问当a不再需要这块内存,能否直接释放它?答案是否定的。因为a并不知道b是否还在使用这块内存,如果a释放了,那么b在使用这块内存的时候会引起程序crash掉。 

(2)知道了上述assign的问题,那么如何解决呢?最简单的一个方法就是使用引用计数。我们给那块内存设一个引用计数,当内存被分配并且赋值给a时,引用计数是1。当把a赋值给b时,引用计数增加到2.这时如果a不再使用这块内存,他只需要引用计数减1,表明自己不再拥有这块内存。b不再使用这块内存时也把引用计数-1.当引用计数变为0的时候,代表该内存不再被任何指针所引用,系统可以把它直接释放掉。 

小结:assign就是直接赋值,从而可能引起1中的问题,当数据为int,float等原生类型时,可以使用assign。retain使用了引用计数,retain引起引用计数+1,release引起引用计数-1.当引用计数为0时,dealloc函数被调用,内存被回收。 

********************************************

https://www.cnblogs.com/Jenaral/p/5970393.html

retain:他指的是将某个内存区域的指针赋值给变量,同时把该内存区域的引用计数器加1.每执行一次,该内存区域的引用计数器就要加1,当该区域的引用计数器变为0的时候内存区域被释放!

 

copy:它指的是将目标内存区域的值复制一份,然后开辟新的内存区域(新的指针)粘贴这个值。同时变量被赋值为新内存区域的指针!

 

assign:它指的是,仅只把目标内存区域的指针赋值给变量,该内存区域的引用计数器不发生变化!

 

1、2两点不做解释,3中的retain、copy、assign都是指的,在自动生成setter函数的时候,编译器需要识别个描述词来生成对应的setter函数!需要注意的是,如果没有加上该类的描述词,系统默认该变量的setter方法采取assign的方式。

*******************************************

2、属性的存取方法

一般情况下,一旦你使用@property声明了一个属性,编译器就会自动为该属性生成一对存取方法。编译器生成的存取方法遵守以下命名约定:

1)用来访问属性值的方法,getter方法,其名字与属性的名字是相同的;还可以把存取设置为想要名字;

2)用来设置属性值的方法,setter方法,其名字以“set”开始,其后是属性名,属性名首字母大写;

属性的修饰也会告诉编译器如何生成相关的存取方法,对于readonly属性,编译器会生成getter方法,但不会生成setter方法。

你也可以为存取方法取一个你自己想要的名字:同上1)

[objc]

view plain 

copy

  @property (getter=isFinished) BOOL finished;  

[objc]

view plain 

copy

  @property (readonly, getter=isFinished)BOOL finished;  

除了明确调用存取方法之外,OC还提供了点语法,来访问对象的属性:

[objc]

view plain 

copy

  NSString *firstName = somePerson.firstName;  

[objc]

view plain 

copy

  somePerson.firstName = @”Johnny”;  

点语法只是存取方法调用的一个便捷方式。当你使用点语法的时候,属性依然是通过getter或者setter方法来访问或者改变的。

点语法访问属性,同样要受到属性修饰的约束。

3、属性与实例变量

默认地,一个可读写的属性是基于一个实例变量的,这个实例变量也是编译器自动生成的。

自动生成的实例变量与属性的名字是相同的,但是多了一个下划线前缀。

尽管一个对象通过存取方法或者点语法访问自己的属性是最佳做法,但是它也可以在类实现中的,任何实例方法中,直接访问该属性对应的实例变量。下划线前缀清晰地表明你正在访问一个实例变量,而不是一个局部变量:

[objc]

view plain 

copy

– (void)someMethod {  

  NSString *myString = @”An interesting string”;  

  _someString = myString;  

}  

一般而言,你应该使用存取方法或者点语法来访问属性,即使你是在它自己的类实现中访问其属性,在这种情况下,你需要使用self:

[objc]

view plain 

copy

– (void)someMethod {  

  NSString *myString = @”An interesting string”;  

  self.someString = myString;  

  // or  

  [self setSomeString:myString];  

}  

self在object-c中代表当前实例。这个规则的例外会出现在当你写初始化、释放内存或自定义存取方法的时候。

四、对象与方法

1、方法

在Object-C中,有两种类型的方法,类方法和实例方法。

类方法以+开头,其基本形式如下:

+ (id)someMethod;

类方法一般都是工厂方法,返回一个实例。

实例方法以-开头,其基本形式如下:

- (void)someMethod;

方法可以不带参数,也可以带一个或多个参数,也可以有返回值:

[objc]

view plain 

copy

– (int)someMethod;  

– (void)someMethodWithValue:(SomeType)value;  

– (void)someMethodWithFirstValue:(SomeType)value1  secondValue:(AnotherType)value2;  

2、对象的创建与初始化

Object-C的对象的内存都是动态分配的,所以要使用指针来记录一个对象。

NSObject根类提供了一个类方法,alloc,用来为对象动态分配内存:

+ (id)alloc;

注意该方法的返回值是一个id类型,它表示指向一个对象的指针。

alloc方法还有一个重要的任务,就是清理分配给对象属性的内存,通过将其置为0。也就是说会它会帮你初始化对象的属性。

与+

(id)alloc对应的就是- (void) dealloc,它用来释放对象的内存,自动引用计数ARC会自动调用该函数,而不用我们手动调用。

NSObject还提供了对象的初始化方法:

– (id)init;

这是一个实例方法。在init函数中你可以为对象的属性赋予合适的初值。

与-

(id)init对应的是- (void) release,调用该函数会使得对象的引用计数-1,引用计数为0的话呢,ARC就会调用-

(void) dealloc释放掉对象的内存。

3、消息

对象可以发送和接受消息,一个对象通过调用该对象的一个方法发送一个消息给另一个对象。这是object-C的说法,说白了就是函数调用。

对象发送消息的最常见形式如下:

[objc]

[someObject doSomething];  

[someObject doSomething: someValue];  

对象可以给自己发送消息:

[objc]

view plain 

copy

  [self saySomething:@”Hello, world!”];  

对象可以调用其父类实现的方法:

[objc]

view plain 

copy

  [super saySomething:@”Hello, world!”];  

五、类扩展

类扩展一般在实现文件的最上部实现,用于扩展类的内部实现。

你可以在类扩展中声明一个属性:

[objc]

view plain 

copy

  @interface yourClass ()   

  @property someType someProperty;  

  @end  

在类扩展中声明的属性,编译器同样会为其生成相关的存取方法和实例变量。但是它只能在类的实现内部进行访问。

你也可以声明一个实例变量(不是属性的实例变量):

[objc]

view plain 

copy

  @interface yourClass ()   

{  

     someType someValue;  

}  

  @end  

这个实例变量也只能在类的实现内部访问。

你还可以在类扩展中声明方法:

[objc]

view plain 

copy

  @interface yourClass ()   

 -(void)someMethod;  

  @end  

这个方法需要在类实现中进行实现,并且只能在类实现中进行调用。

综合起来,.m文件的基本格式如下:

[objc]

view plain 

copy

  #import  “yourClass.h“  

  @interface yourClass ()   

{  

     someType someValue;  

}  

[objc]

view plain 

copy

  @property someType someProperty;  

[objc]

view plain 

copy

  -(void)someMethod;  

  @end  

一些需要注意的问题,有一些上面提到过,再过一遍吧:

1、程序的头文件和源文件的扩展名分别为.h 和.m;

2、注释:单行(//)和多行(/* … */);

3、Object_C 中的nil 相当于NULL。

4、Object_C 中的YES 和NO 相当于true 和false。

5、#import相当于#include

,导入头文件也有两种查找方式< … > 和” … “,但是#import 可自动防止同一个文件被导入多次。

6、Object_C中的所有类都必须继承自NSObject。

7、Object_C仅支持单一父类继承,不支持多重继承。

8、Object_C中所有对象都是指针的形式。

9、Object_C用self代替this。

10、Object_C使用id代替void*。

11、Object_C中用消息表示类的方法,并采用[aInstance

method:argv]调用形式。

12、Object_C支持反射机制。

13、Object_C支持Dynamic Typing,Dynamic

Binding和Dynamic Loading。

本篇知识点回顾:

1、了解OC语言的基本特性;

2、掌握类的声明、实现;

3、掌握属性的声明和修饰;

4、掌握对象的创建和方法的声明及实现。

    原文作者:wenjunyeah
    原文地址: https://www.jianshu.com/p/63ccafe57f2b
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞