Objective-C复习笔记

Objective-C简介

Objective-C简称Objc或者OC,是一种基于C语言的面向对象程序设计语言。1980年代产生,主要在苹果电脑平台上使用,开发Cocoa或Cocoa Touch应用程序。
通过LLVM编译器架构,可以苹果家最新的编程语言Swift进行双向操作。不过终有一天将会被Swift取代。

开发方式

命令行

clang -fobj-arc *.m
-fobj-arc表示支持ARC内存管理
适合研究、调试、学习

IDE

通过Xcode构建正规工程项目
有利于构建高质量的代码组织

类与对象

在OC中所有的类都是引用类型,所有c语言中的基本数值类型都是值类型。此外,详细的类型说明如下表所示:

引用类型(reference) 值类型(value type) 类型装饰
类 class 基础数值类型 协议 protocol
指针 pointer 结构 struct 类别 category
快 block 枚举 enum 扩展 extension

类与结构体的区别

类 class 结构 struct
实例 对象
类型 引用类型(栈:指针,堆:实体对象) 实例直接存在在栈中

栈和堆的区别

栈 stack 堆 heap
存储类容 值类型 引用类型的对象
管理方式 由系统自动管理,函数为单位 分配由程序员手动请求
具体 空间大小编译时确定(参数+全局变量) 释放由运行时ARC机制自动释放(确定是)
具体 函数执行时,系统自动分配stack
具体 函数结束后,系统立即自动回收stack
传递方式 函数间直接通过拷贝值传递 函数间通过拷贝引用(指针)传递
限制 有局部性,大小有限额,超出stack overflow 有全局性,无大小限制(受制系统内存大小)

属性与实例变量

数据成员描述对象的状态:1.实例变量instance variable。2.属性property。

属性

属性描述的是对象的状态,是对外的接口(相当于是public)。
声明一个属性的同时,编译器会自动为这个属性生成:
1.getter访问器方法: properyName
2.setter访问器方法: setProperyName
3.一个对应的实例变量: _propery

访问器方法可以自定义。访问器方法名也可以修改。对应的实例变量名也可以修改。但是一般使用编译器默认生成的,以便统一规范。

使用静态全局变量(c语言)+类方法,可以模拟类属性。

实例变量

可在不声明属性的情况下定义实例变量。只有实例变量,无类变量。
若单独自定义了访问器方法,则编译器就不在合成实例变量。
类外使用属性来访问,类内一般也是用属性访问即self.
以下情况例外:
初始化器 init
析构器 dealloc
自定义访问器方法中

生存周期
实例变量存储在堆上。
值类型实例变量内嵌在对象实例中,随着对象实例释放。
引用类型的实例变量通过指针引用堆上的实例,ARC对引用进行计数管理,自动施放。

属性的描述特性
Attribute可指定属性的不同功能。

读写: readwrite(默认),readonly
多线程: atomic(默认), nonatomic

内存管理特性
ARC下:
strong(默认), weak(阻止循环引用), copy(创建独立拷贝)
MRC下:
retain
assign
unsafe_unretained

方法

函数成员描述对象的行为:1.方法method。2.初始化器init。3.析构器dealloc。

函数指的是代码段上可执行指令序列,OC中称为方法。
所有的方法默认都是公有的,没有private和protected。
方法调用通过运行时动态消息分发实现,OC中称为向对象发送消息。

方法的类型

实例方法,可访问:
实例成员。
类型方法、静态变量。

类方法
可访问:类型方法、静态变量
无法访问实例成员。

方法的参数

参数为值类型,则为值传递方式;为引用类型,则为指针传递;
方法可以无参数和返回值。

初始化器和析构器

初始化器用于初始化对象实例或类型:
对象初始化:-(id) init 可以重载多个
alloc:1.在堆上分配合适大小内存。2.将属性或实例变量的内存置0。
init:1.调用父类初始化器[super init]。2.初始化当前对象实例变量。
new相当于alloc/init的无参数版本。
类型初始化:+(void) initialize 只能一个
负责类型级别初始化。
每个类使用前被系统自动调用,每个进程周期只调用一次。
子类调用父类的initialize方法。

析构器用于释放对象的资源,无返回值。
只能一个。
无类型析构器。

自动:ARC将对象属性引用计数减持。
手动:1.释放不受ARC管理的动态内存,如malloc。
2.关闭非内存资源,如文件句柄,网络资源。

dealloc由ARC自动在释放对象内存前调用,无法手工调用。
子类dealloc会自动调用父类的dealloc(后置调用)。

继承与多态

继承的含义:
成员复用:子类复用父类成员
类型抽象:将子类当做父类使用(IS-A关系准则)

多态:
子类在父类统一行为接口下,表现不同的实现方式。

OC不支持重载,子类只能重写与父类同名同参数方法。

子类中通过super调用父类实现。
self具有多态性,可以指向不同的子类。
super无多态性,仅指向当前父类。

init和dealloc的继承

init:
子类自动继承父类的初始化器。
子类也可以重写父类的初始化器,此时子类初始化器必须先调用父类的一个初始化器。

dealloc:
子类可以选择继承父类析构器或者重写父类析构器。
子类析构器执行完后会自动调用父类的析构器(后置调用,且不支持手工调用)。
子类析构器自动具有多态性。

2016/5/14 22:33 下午 posted in  Objective C

Objective-C中的协议

一.问题的产生


NetworkConnector类提供所有和网络服务器的交互,包括连接、断开连接和手法数据。BusinessLogic类会接收NetworkConnector收到的数据,并确定它的走向。
网络连接是一个在其他应用或同一个应用的其他地方一定会复用的东西。所以必须将它与BusinessLogic类设计成没有紧密耦合。

C++等语言使用多继承来解决这类问题,强制BusinessLogic类继承自NetworkConnector可以依赖的类。但是多继承会产生新的问题,即砖石问题。如果D类同时继承自B类和C类,同时B、C也继承自共同的超类A,这种情况下,如果D没有重写A中的方法,当D调用A类的方法的时候,无法确定会调用哪一个父类的方法B类的还是C类的?
Objective-C只能使用单继承。

二.Objective-C的解决方案

Objective-C使用协议来声明一个接口来解决这个问题。
接口是在不提供默认实现时由一个类来具体实现,它只提供声明这些方法的接口机制,让可复用组件不依赖于特定的类来实现,而依赖于以协议形式存在的接口。

协议的声明

@protocol NetworkClient
@required
-(void) networkConnector:(NetworkConnector *) in gotData:(NSData *) data;
@optional
-(void) networkConnectorDisconnected:(NetworkConnector *) in;
@end

@required关键字表明其后的方法是该协议必须实现的方法。
@optional关键字表明其后的方法是实现类可以选择性实现的方法。
同时,协议不能有成员变量。

声明一个必须实现协议的对象

id<NerworkClient> *delegate; //<>中是该对象必须实现的协议

通常使用id数据类型来声明实现给定协议的实例变量。编译器会通过<>中的协议类型来确认协议的必须按方法是否在该对象上实现了。

非正式协议

它是在Cocoa和Objective-C中的旧协议,通常是NSObject类的类别。

正式协议

正式协议可以提供更好的类型安全。用@protocol关键字来声明。有@required和@optional关键字来保证必须实现的和可选的方法。

避免协议循环依赖

协议在各自的声明中可以引用另一个协议。

@protocol Foo
-(void)someMethodRequiringBar:(id<Bar>)inBar;
@end

如果Bar也需要Foo协议的话,就会导致协议之间的循环依赖,发生编译器错误。

@protocol Bar
-(void)someMethodRequiringFoo:(id<Foo>)inFoo;
@end

解决方法,在Bar.h中加入@protocol Foo,告诉编译器Foo是一个协议,不用导入Foo.h。

2016/4/17 23:12 下午 posted in  Objective C

Objective-C中的类别

刚刚翻看了OC的书中关于类别的一章,现将OC中类别的使用和限制总结如下。

定义及使用

1.通过在类上声明和实现方法来扩展现有类的功能,且不需要访问要扩展类的原有代码。
2.类别不是子类,添加的方法可以直接在操作的类中使用,因此可以避免通过继承的方式添加某些方法的实现。
3.可以通过类别重写现有方法,但一般不推荐,这样会导致无法调用被扩展的类的初始方法,只能访问重写过的方法。

声明

头文件

#import <Foundation/Foundation.h>

@interface NSMutableString (GUID) //括号里为类别的名字

-(void) appendGUID;
+(id) stringWithGUID;
@end

实现

#import "NSMutableString+GUID.h"

@implementation NSMutableString (GUID)

-(void) appendGUID{
    CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
    NSString *string = (NSString *)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, uuid));
    [self appendString:string];
   // CFRelease(uuid);
}

+(id) stringWithGUID{
    NSMutableString *string = [self string];
    [string appendGUID];
    return string;
}

@end

扩展成员方法:可访问类的所有成员变量、可以通过self调用类的其它方法、可以使用super关键字调用父类的方法。self关键字指实例对象。
扩展类方法:无法访问成员变量。self关键字指类对象。

使用

#import <Foundation/Foundation.h>
#import "NSMutableString+GUID.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSMutableString *str = [NSMutableString stringWithGUID];
        NSLog(@"GUID=%@", str);
    }
    return 0;
}

限制

1.类别不能在扩展类中添加任何成员变量。
2.重写现有方法时,无法调用原始现有对象方法。
3.若两个类别都定义了一个相同类的相同方法,运行时实际无法确定调用哪一个。

2016/4/6 0:9 上午 posted in  Objective C