[OC学习笔记]熟悉Objective-C

Posted Billy Miracle

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[OC学习笔记]熟悉Objective-C相关的知识,希望对你有一定的参考价值。

Objective-C使用“消息结构”而非“函数调用”。使用消息结构的语言,其运行时所应执行的代码由运行环境来决定;而使用函数调用的语言,则由编译器决定。采用消息结构的语言,不论是否多态,总是在运行时才会去查找所要执行的方法。
Objective-C是C的“超集”(superset)。
OC中的指针是用来指示对象的。想要声明一个变量,令其指代某个对象,可以:

NSString *someString = @"The string";

所有OC语言的对象都必须这样声明,因为对象所占内存总是分配在“堆空间”(heap space)中,而绝不会分配在“栈”(stack)上。不能在栈中分配OC对象:

NSSring stackString; 
// error: interface type cannot be statically allocated

someString变量指向分配在堆里的某块内存,其中含有一个NSString对象。也就是说,如果再创建一个变量,令其指向同一地址,那么并不拷贝该对象,只是这两个变量会同时指向该对象:

NSString *someString = @"The string";
NSString *anotherString = someString;


分配在堆中的内存必须直接管理,而分配在栈上用于保存变量的内存则会在其栈帧(stack frame)弹出时自动清理。
OC将堆内存管理抽象出来了,不需要malloc及free来分配或释放对象所占内存。OC运行期环境把这部分工作抽象为一套内存管理架构,叫做“引用计数”。
定义里不含*的变量,它们可能会使用“栈空间”(stack space)。这些变量所保存的不是OC对象。比如CoreGraphics框架中的CGRect:

CGRect frame;
frame.origin.x = 0.0f;
...

CGRect是C结构体,其定义:

struct CGRect {
	CGPoint origin;
	CGSize size;
}
typedef struct CGRect CGRect;

改用OC对象,性能会受影响。

在类的头文件中尽量少引入其他头文件

例:

//EOCPerson.h
#import <Foundation/Foundation.h>
//#import <EOCEmployer.h>
//不在此引入头文件
@class EOCEmployer;
//使用向前声明(forward declaring)
@interface EOCPerson : NSObject
@property (nonatomic, copy) NSString *firstName;
@property (nonatomic, copy) NSString *lastName;
@property (nonatomic, strong) EOCEmployer *employer;

EOCPerson的实现文件则要引入EOCEmployer类的头文件,因为需要知道其所有接口细节来使用它。
将引入头文件的时机尽量延后,只在确有需要时引入,这样可以减少类的使用者所引入头文件的数量。否则会增加编译时间。
向前声明也解决了两个类相互引用的问题。假设要为EOCEmployer类加入新增及删除雇员的方法,那么其头文件会加入如下定义:

- (void)addEmployee:(EOCPerson*)person;
- (void)removeEmployee:(EOCPerson*)person;

如果在各自头文件中引入对方头文件,则会导致循环引用(chicken-and-egg situation)。这会导致两个类里有一个无法被正确编译。
有时无法使用向前声明,比如要声明某个类遵循一项协议。这种情况下,尽量把“该类遵循某协议”的声明移至“class-continuation分类”中,如果不行的话,就把协议单独放在一个头文件中,然后将其引入。

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

字面数值:

NSNumber *someNumber = [NSNumber numberWithInt: 1];
//下面的代码更加整洁:
NSNumber *someNumber2 = @1;
//此外,其他数据类型也可以使用字面量语法:
NSNumber *intNumber = @1;
NSNumber *floatNumber = @2.5f;
NSNumber *doubleNumber = @3.14159;
NSNumber *boolNumber = @YES;
NSNumber *charNumber = @'a';
//也适用于:
int x = 5;
float y = 6.32f;
NSNumber *expressionNumber = @(x * y);

字面量数组:

NSArray *animals = [NSArray arrayWithObjects: @"cat", @"dog", @"mouse", @"badger", nil];
//字面量语法:
NSArray *animals2 = @[@"cat", @"dog", @"mouse", @"badger"];

NSString *dog = [animals objectAtindex: 1];
NSString *dog2 = animals[1];

使用字面量语法创建数组时,若数组元素对象中有nil,会抛出异常。arrayWithObjects:方法会依次处理各个参数,直到发现nil为止。这个差别说明,使用字面量语法更安全,抛出异常令程序终止执行,这比创建好数组后才发现元素个数少了要好。向数组中插入nil通常说明程序有错,而通过异常可以更快地发现这个错误。
字面量字典:

NSDictionary *personData = [NSDictionary dictionaryWithObjects:
	@"Matt", @"firstName",
	@"Galloway", @"lastName",
	[NSNumber numberWithInt: 28], @"age",
	nil];

NSDictionary *personData2 = 
	@{@"Matt", @"firstName",
	  @"Galloway", @"lastName",
	  @"age" : @28};
//与数组一样,用字面量语法创建字典时也有个问题,那就是一旦有值为nil,便会抛出异常。

NSString *lastName = [personData objectForKey:@"lastName"];

NSSrting *lastName2 = personData[@"lastName"];

可变数组与字典:

[mutableArray replaceObjectAtIndex:1 withObject:@"dog"];
[mutableDictionary setObject:@"Galloway" forKey:@"lastName"];

mutableArray[1] = @"dog";
mutableDictionary[@"lastName"] = @"Galloway";

局限:
想创建自定义子类的实例,必须采用“非字面量语法”。
使用字面量创建的字符串、数组、字典对象都是不可变类型。若要可变版本,则需要复制一份:

NSMutableArray *mutable = [@[@1, @2, @3]mutableCopy];

以上是关于[OC学习笔记]熟悉Objective-C的主要内容,如果未能解决你的问题,请参考以下文章

Objective-C学习笔记-第二天

IOS开发-OC学习-常用功能代码片段整理

[OC学习笔记]自动引用计数

Objective-C学习笔记

[OC学习笔记]自动引用计数初学

[OC学习笔记]ARC与引用计数