第十章 对象初始化

分配对象

两种方式:[[Object alloc] init]或者[Object new]
使用alloc init进行对象的创建比new要来的好 原因
alloc执行会将内存区域置为0
不能使用Object *obj = [obj alloc]; [obj init];这样的方式,因为init返回的对象可能和分配的对象不一样
初始化方法一般这样编写:

便利初始化

NSString中的- (id) initWithFormat: (NSString) format, …; 可以用来代替init函数进行初始化
NSString中的- (id) initWithContentsOfFile: (NSString) path encoding: (NSStringEncoding) enc error: (NSError **) error;其中encoding表示编码类型,NSUTF8StringEncoding表示UTF-8编码,最后一个参数表示error,如果这个值不是nil的话就表示出错了,可以用localizedDescription查看情况

这里的localizedDescription表示错误的本地化描述
一般来说最好的办法就是定义一个指定初始化函数,最好使用一个最多参数的函数作为指定初始化函数,其他所有的函数都基于这个指定初始化函数来写
那么子类只需要重写指定初始化函数就可以实现类的初始化

内存管理

在管理内存的时候,dealloc中一定要释放所有的内存,并在最后调用[super dealloc]

第十一章 属性

属性

@property表示定义出来的变量具有float属性

@synthesize会自动创建该属性的getter和setter,并且在synthesize的时候,编译器会自动创建与属性名称相同的变量,实例变量也可以在@implementation中用{}代码块(类似于@interface中的方法)来获得
在Objective-C2.0以上,可以使用类似于C++的点表达式来访问成员变量

以上两组代码都是等价的
@property (copy) NSString *name;表示以后name会被复制,这样程序员就会知道自己无需复制文本框内的字符串
@property (retain) Engine *engine; 表示以后engine只有保留额释放特性,retain表示指针拷贝
要注意的是,我们如果没有setter和getter的话,我们是无法访问变量的

因为是非gc的对象,所以默认的assign修饰符是不行的。那么什么时候用assign、什么时候用retain和copy呢?推荐做法是NSString用copy,delegate用assign(且一定要用assign,不要问为什么,只管去用就是了,以后你会明白的),非objc数据类型,比如int,float等基本数据类型用assign(默认就是assign),而其它objc类型,比如NSArray,NSDate用retain。

如果两者都没有使用的话,默认会使用assign
在IOS程序中nonatomic可以提升访问速度,如果自定义了setter和getter的话,就不能使用atomic特性了,必须使用nonatomic
如果在Car类中要使用其他名称来调用实例变量,那么只需要在头文件中修改变量名称并在.m文件中使用@synthesize name = 变量名; init中要将name= @”Car” self.name = @”Car”

只读属性

@property (readwrite, copy) NSString *name;
@property (readwrite, retain) Engine *engine;
一般来说我们不用特意声明读写的属性,因为默认就是可读写的
如果需要只读,那么只需要用成
@property (readonly) float shoeSize;
类似这样的方法就可以了
这是如果调用- setShoeSize:方法就会报错

dynamic

@dynamic告诉编译器不要创建getter、setter和变量
例如:
如果没有定义则会出现报错
@property (getter=isa) BOOL a;
这样的话getter就是isa了
要注意的是,我们只能重载getter和setter等,而不能重写别的函数

第十二章 类别(category)

@interface部分

特点是括号中有一个新名称,意味着给他加了一个类别,只要类别名称唯一,你就可以像一个类中添加任意数量的类别,要注意的是,类别中不可以添加实例变量
概念:类名、类别名

@implementation部分

可以在这里实现自己的方法
概念:类名、类别名,方法的实现

个人理解:类别差不多就是对类提供了一个操作的集合,可以理解为一个类的特殊子类,但是这个特殊子类里面不能包含实例变量
使用的时候使用如下代码:

注意:类别方法和方法冲突的时候,类别方法拥有更高的优先级

类扩展

第二部分的代码中,重写了thing2,添加了方法thing3和实例变量thing4,这里面的代码都是私有属性和方法,上面的则是公有的,对于thing2来说,上面的方法是它的公共接口,下面的方法是它的私有接口。
注意:多个类扩展会出现可能难以察觉的Bug,且容易影响代码可读性
类别可以用来分散代码,就是说将一堆方法分散到逻辑群组中,使得程序员更容易阅读头文件

通过类别创建前向引用

原因:如果调用方法的时候未声明对象的某个方法的话,那么就会找不到该方法的声明和定义
所以我们可以声明一个方法,其中的常用策略就是将类别置于实现文件的最前面,实现的时候尽量还是在@implementation中实现,否则编译器仍然会报警告

非正式协议

interface这么声明
@interface A : NSObject <NSNetServiceBrowerDelegate>
告诉编译器A这个类符合这个协议
定义一个非正式协议只需要定义一个NSObject的一个类别即可,不需要实现这个类别,工程中不经常使用到

第十三章 协议

正式协议

正式协议采用@protocol关键字来实现的,并且和非正式协议不同的是,正式协议只能显式调用
可以继承父协议,与继承父类类似,使用尖括号表示继承
协议名称必须要唯一
需要使用协议或多个协议,则使用以下语法:
NSZone指向一部分可分配的内存区域,使用的时候注意先使用Zone
实例变量可以使用->运算符访问
运用某个协议的类,则需要实现这个协议的所有@required友元方法
@required表示必须实现的方法
@optional表示可选实现的方法
用协议修饰变量、函数:

变量myNewVariable和doSomethingWithThisObject: 的参数都需要遵循MyProtocolName协议

委托

目的:将A的事情委托给B来做

  1. 在A中声明协议,即要委托出去的事情(方法)。
  1. A中声明一个委托对象,即要委托给谁去办,用id<协议名字>委托对象名;
  1. 比如想让B做A的事情,那么B的interface中要宣布自己遵循A中制定的那个协议。
  1. A调用委托执行那件事情去.即[delegate fun]

第十四章 代码块

代码块

和老式的函数指针对应
个人感觉:和lambda匿名函数差不多
特性如下:
  1. 返回类型可以手动声明也可以自动推导;
  2. 具有指定类型的参数列表
  3. 拥有名称
正常的函数指针:

将这个函数指针的*更换为^就是代码块了

一般来说可以用以下的关系来表示他们:

函数方法使用代码块

我们可以通过直接调用blockname来像使用函数一样使用这个代码块
代码块可以访问与它相同的(本地)有效范围内声明的变量,也就是说代码块可以访问与它同时创建的有效变量,例如在定义代码块前定义一个变量,则代码块可以使用这个变量

直接使用代码块

使用typedef关键字

注意:代码块在定义的时候会保存在定义的时候所有本地变量的状态,即使在后面更改了变量的值,也不会影响代码块运行的结果,要改变这种状态的话,需要使用static关键字来创建全局变量,对于全局变量代码块是能看到的

参数变量

参数变量和函数中的参数变量类似

__block变量

这个变量类型表示该变量可以被在它作用域以内的代码块修改,类似这样定义__block double c = 3;

代码块内部的本地变量

该变量类型和本地变量的类型差不多

OC变量

  • 如果引用了一个OC对象,必须要保留它
  • 如果通过引用访问了一个实例变量,要保留一次self(即执行方法的对象)
  • 如果通过数值访问了一个实例变量,变量需要保留
参考书上P223,很详细

0 条评论

发表评论

邮箱地址不会被公开。 必填项已用*标注