About Objective-C
Objective-c 是在为ios和mac的设备写app的主要语言,它是c的超集并且提供面向对象的能力和dynamic run time;
objective-c继承了c的语法和原始的类型以及c的流程控制,并在此基础上添加了定义类和方法的语法结构。他也为对象图形管理和对象排版添加了一些语言学的支持,同时也提供了动态类型和binding,把这些责任推迟到运行时
At a Glance
这篇文档介绍了objective-c语言并且他的使用的一些扩展的例子,从这篇文档将学到怎样创建一个描述你自己类的对象,怎样与cocoa与cocoa touch提供的框架类协同工作。尽管框架类并不属于objective-c语言,但许多语言级的特征取决于这些类所提供的行为An App Is Built from a Network of Objects
当你在构建app时,你的大部分时间都在和object打交道,这些对象都是objective-c类的实例,一些对象是由cocoa touch或cocoa提供,一些对象是由你自己写的如果你自己写一个类,你就要提供这个类详细的公共接口,接口包括封装相关数据的属性。通常还列出一些方法。方法的声明表明了一个对象所能接受的信息,包含了方法在调用时所需要的参数。在类的实现中,包含了在接口中所声明的方法的实现代码
Categories Extend Existing Classes
当需要为一个存在的类提供一些附加的功能时,通常不需要重新定义这个类,而是用category为存在的类添加一些行为。可以用category为任何类添加方法,包括不是你自己实现的源代码,例如NSString如果你有一个类的源代码,可以用类的扩展去添加一些新的属性,或者更改存在的属性
Protocols Define Messaging Contracts
在objective-c app中,对象通常要相互之间发送信息,这些信息通常是在interface中都有明确的声明。但是有时候需要定义一些相关的方法,但是这些方法并没有特别指定是属于哪一个类的。在objective-c中,用protocol支持定义这样一个方法的集合,这些方法我们通常把他叫做delegate,任何类都能采纳一个协议,但采纳这个协议的类必须实现这个协议中所有required方法。Values and Collections Are Often Represented as Objective-C Objects
通常在objective-c中用cocoa touch类去代表某个值,NSString类代替c中的string,NSNumber类是不同类型number的集合,NSValue类代替C结构体,当然也能够用原始的数据类型如int,float等
Blocks Simplify Common Tasks
Blocks是一个被c,objective-c和c++所引进的代表一个工作单元的语言特征,用blocks通常简化常见的任务如:collection enumeration,sorting和test,
Error Objects Are Used for Runtime Problems
尽管objective-c包含了异常处理的语法
Objective-C Code Follows Established Conventions
在写objective-c代码的时候,你应该遵守一些约定俗成的规则。比如方法的名字首字母要小写一 Defining Classes
当你为os x或者ios写app时,大部分的时间将花费在object上,objects用相关的行为封装了数据。一个app是一个由对象组成的大的生态系统,在这个对象系统中各个对象相互联系相互作用共同去解决一个特定的问题,例如显示一个可视化的接口,对用户的输入做出响应或者存储信息,cocoa或cocoa touch库中包含了许多已经存在的对象。
在cocoa或cocoa touch库中一些对象是立即可用的,例如基本的数据类型strings和numbers等,例如基本的用户界面元素buttons或table views。
当然也可以自己定义一个对象,自己定义它的行为。app开发的过程就是用自己定义的对象和cocoa 所提供的对象协同合作去完成某个功能
在面向对象的实例中,一个对象就是一个类的实例。自己定义一个类,首先要声明一个interface,interface中声明了属性和方法,还需要一个implementation,在那里实现在interface中所声明的方法
Classes Are Blueprints for Objects
类描述了特定类型对象的行为和属性,每一个类的实例都share相同的行为和属性Mutability Determines Whether a Represented Value Can Be Changed
一些类所定义的对象是immutable,这意味着当对象被创建的时候,它内部的contents必须被设定,随后不能被别的对象所改变在objective-c中,NSString和NSNumber都是immutable的
但都提供了mutable的版本,
Classes Inherit from Other Classes
当一个类从父类继承的时候,这个类继承了父类所定义的所有的方法和属性,这个类也能定义他自己的行为和属性,或者覆盖父类的行为The Root Class Provides Base Functionality
在objective-c中,一些方法或属性是所有的对象所共有的,在objective-c中,定义了NSObject类是所有类的父类,The Interface for a Class Defines Expected Interactions
Use Pointers to Keep Track of Objects
用指针来追踪内存中的对象
在方法中的指针与local variable一样,生命周期在方法内部,当脱离方法之后,指针变量消失,但指针所指向的对象还在内存中
Objects Can Send Messages to Themselves
当在写一个方法的实现时,已经获取了一个重要的隐藏值self,self是一种参考到接受到这条信息的对象的一种方式,self就是一个指针,能够调用当前对象的一个方法。
Objects Can Call Methods Implemented by Their Superclasses
在objective-c中还有另外一个关键字super.,发送信息给super,调用父类所实现的方法。通常在覆盖一个方法中调用super.Objects Are Created Dynamically
内存为对象动态的分配空间,创建对象的第一步就是要确保有足够的内存去分配,不仅要为对象所属类定义的property分配内存,也要为类的父类中定义的property分配内存
root class提供了class method:alloc来handle内存的分配
alloc的返回值是ID,ID是一个指针,这个指针指向一种未知类型的对象
alloc方法有一个重要的任务,就是清除为对象的属性所分配的内存并设定他们为0.这样做避免了内存中包含垃圾数据,不能够完全初始化对象
通常alloc与init同时使用,init确保对象的属性值在创建的时候由一个合适的值,
init的返回值也是id
Initializer Methods Can Take Arguments
Class Factory Methods Are an Alternative to Allocation and Initialization
类也定义了自己的构造方法,在类的构造方法和alloc,init之间可以选择任何一个。Use new to Create an Object If No Arguments Are Needed for Initialization
可以用class的new方法去创建一个class的实例,new方法是有NSObject所提供的,等效于调用alloc和init没有参数Literals Offer a Concise Object-Creation Syntax
还可以用简洁平实的方法来创建实例如NSString *someString = @"I an a string"; 创建了一个NSString类的实例
上面的创建等价于:
NSString *someString =[ [NSString alloc] initWithCString:"hello world" encoding:NSUTF8StringEncoding];
Objective-C Is a Dynamic Language
用指针去追踪内存中的对象
Determining Equality of Objects
==isEqual
compare
Working with nil
在声明标量值是总是初始化它如:
BOOL success = NO;
但是对指向对象的指针,没有必要让一个指针指向nil,在默认情况下,指针总是指向nil,在objective-c中发送一个信息给nil是安全的。如果发送一个信息给nil将不会做任何事情
检查一个对象是否是nil
if(someObject !=nil){
}
或
if(someObject){
}
如果someObject是nil,他就没有地址,someObject就为假
二 Encapsulating Data
对象通常通过属性来封装数据Properties Encapsulate an Object’s Values
大部分数据为了去执行他们的任务而需要去追踪信息Declare Public Properties for Exposed Data
一个属性有两个获取方法:setter和getter方法getter方法的名字与property的名字一样
setter方法的名字在property的名字前加set
也可在属性声明时指定获取方法
@property(strong,getter = isFinished) BOOL finished
Dot Syntax Is a Concise Alternative to Accessor Method Calls
Most Properties Are Backed by Instance Variables
在默认情况下,实例变量的默认属性是readwrite property,自动被编译器人工合成一个对象的实例变量在对象的生命周期内能够存在和保持它的值。当对象第一次被创建时,内存就会为实例变量分配内存,在重新分配对象时就会释放这些实例变量
合成实例的名字与属性名字一样,但在属性名字前多了_;
You Can Customize Synthesized Instance Variable Names
如果你不想用默认的instance variable,可以指定一个instance variable:@synthesize propertyName = instanceVariableName;
You Can Define Instance Variables without Properties
Access Instance Variables Directly from Initializer Methods
setter方法有附加的边际效应,可能触发KVC notification,或者执行进一步的任务在初始化方法中总是直接获取实例变量,因为在属性被设置的时候,对象还没有完全的初始化
通常一个初始化方法应该像这样:
-(id)init{
self = [super init];
if(self){
_firstName = aFirstName;
_lastName = aLastName;
}
return self;
}
The Designated Initializer is the Primary Initialization Method
在一个对象中如果有一个或多个初始化方法,需要指定designated 初始化方法You Can Implement Custom Accessor Methods
Properties Are Atomic by Default
Atomic意味着合成存储器即使在多个线程同时调用他,他所获取的值或设定的值总是成对出现的。Manage the Object Graph through Ownership and Responsibility
objective-c中的内存被动态的分配,需要用指针去追踪这个对象
考虑两个对象之间的关系
当一个对象以某种方式依赖other对象时,这个对象就获取了other 对象的所有权,也就是说别的对象有一个strong reference指向这个 对象,在objective-c中,当有一个strong reference指向一个object时,那这个对象就会keep alive,
当XYZPerson Object重新分配的时候,如果没有别的strong refernce指向这两个NSString对象的话,他没也会重新分配,
Avoid Strong Reference Cycles
strong reference从对象与对象的关系上去管理对象,但如果在一个对象群中,如果有对象的联系形成一个循环,那这些对象将永远keep alive;
一个潜在的reference cycle存在的例子是tableView对象和他的delegate之间的关系
table view有一个strong reference 指向他的delegate对象,这个delegate对象有一个strong reference指向table view
,
如果别的对象放弃了指向table view和delegate的指针
这样就会产生memory cycle,
解决memory cycle的方法就是用一个weak reference代替strong reference
当别的对象不再指向他时
此时delegate object就会被内存释放
Use Strong and Weak Declarations to Manage Ownership
当地变量总是保持strong referenceUse Unsafe Unretained References for Some Classes
有些类不支持weak reference,包括NSTextView,NSFont,所以需要__unsafe_unretained unsafeReference
__unsafe_unretained与weak一样,但当他所指向的对象被重新分配时,指向这个对象的指针将不会被分配为nil.这是如果有信息发送给该对象时,将会是程序崩溃
Copy Properties Maintain Their Own Copies
三 Customizing Existing Classes
对象应该有清晰并且定义好的task, 比如modeling special information,display visual content,controlling the flow of information,正如你所看到的,一个类的interface定义了这个对象与别的对象之间的交互的方式,,这些对象一起协作完成task
但有时候在某种情况下可能需要扩展存在的类,给这些类添加一些行为,例如在应用中你需要显示一个字符串,不需要每次需要显示字符串的时候都去创建一个字符串画的对象,最好的就是给让NSString 对象本身有画字符串的能力
在这种情况下,你不能添加行为给NSString对象,因为并非所有的NSString对象都需要画的能力
Objective-c允许你通过category或class extension去添加自己的方法到存在的类
Categories Add Methods to Existing Classes
你想要添加方法到存在的类,或者在你自己的应用程序中添加一些功能使得做某些事情十分的容易,最简单的方式就是用categories声明一个category的语法:比较像标准objective-c的描述,但没有父类的继承,取而代之的是categoryName.
@interface ClassName(categoryName)
@end
一个category可以为任何类声明,即使你没有任何的关于这个类的实现代码,你在category中声明的所有方法对所有的original 类的实例都是可用的,其中也包括original class的子类,在runtime,在category中的方法与在original class中的实现的方法是没有任何区别的
一个category通常声明在一个单独的header file中,在一个单独的source code file中实现
#import "XYZPerson.h" |
|
@interface XYZPerson (XYZPersonNameDisplayAdditions) |
- (NSString *)lastNameFirstNameString; |
@end |
在一个category中的方法对这个类及其子类都是可用的,但是需要预先声明
category的实现可能像这样
#import "XYZPerson+XYZPersonNameDisplayAdditions.h"
@Implementation XYZPerson (XYZPersonNameDisplayAdditions)
- (NSString *)lastNameFirstNameString{
return [NSString stringWithFormat:@"%@ %@",self.lastName,self.firstName];
}
@end
一旦你为某个类添加了category方法,并且也实现了这个方法,那么在这个类及其子类中都可用这个方法,在category中的所有的方法就等价于original class中声明并实现的方法
象用category添加方法一样,也可以用category把一个存在的比较复杂的类分成多个源代码文件
category适合于去声明class method或者实例方法,但不适合于添加property,
在一个category中添加一个属性语法上是合理的,但不能在category中添加一个实例变量,也就是说编译器不能合成一个instance variable,也不能合成任何的获取方法
当然你可以在category的实现文件中自己写property的获取方法,但你不能追踪这个属性的值,除非这个属性在original class中存储
因此需要为存在的类添加property的唯一方式就是添加class extension
Avoid Category Method Name Clashes
因为category的声明是添加到一个存在的class中的,因此你要避免category中method的名字与original class的method的名字发生冲突如果category中声明的方法的名字与original class的名字相同或者与在original class的别的category中声明的方法的名字相同,那么在run time,运行那一个实现的方法将是不可预知的
例如用到远程网络服务的一个应用,可能需要用base64 coding对一个字符串进行编码
为了避免无法确定的行为,最好的方法就是给category的方法名添加一个前缀,
Class Extensions Extend the Internal Implementation
class extension和category有点相像,具体语法:
@interface ClassName()
@end
一般放在一个custom类的实现文件中,可以隐藏这个类的一些属性
没有名字的category
class extension能够添加自己的属性和instance variable到一个类中,在类的扩展中声明了一个属性:
@interface XYZPerson()
@property NSObject *extraProperty;
@end
编译器会自动综合属性的获取方法,这个属性同在original class中声明的property
Use Class Extensions to Hide Private Information
一个类的公共接口Consider Other Alternatives for Class Customization
面向对象的最主要的目标是写一些可以重复使用的代码,那就意味着类可以重复使用,例如当你创建了一个view class时,你可能需要在多种情况下使用一种是用继承
另外一种是用delegate object
Interact Directly with the Objective-C Runtime
app的运行需要一个运行时系统,可以直接和运行时系统进行交互
四 Working with Protocols
Protocols Define Messaging Contracts
Protocols Can Have Optional Methods
Check that Optional Methods Are Implemented at Runtime
如果一个方法在protocol中标记为optional,在调用他之前你必须检查对象是否实现了该optional methodnil
.
Protocols Inherit from Other Protocols
可以设定协议遵从另外一个协议Conforming to Protocols
这表明MyClass不仅仅能够对在interface中的方法进行响应,也能够对MyProtocol中的方法进行响应,MyClass必须对协议中required的方法进行实现
没有必要在class 的interface中重新声明协议中声明的方法。
如果一个类需要采纳多个协议:
@interface MyClass : NSObject <MyProtocol, MyProtocol1,MyProtoocol2>
@end
Cocoa and Cocoa Touch Define a Large Number of Protocols
Protocols Are Used for Anonymity
id <XYZFrameworkUtility> utility = [frameworkObject anonymousUtility];
五 Values and Collections
在cocoa或cocoa touch中也有一些附加的标量类型可用,NSInteger,NSUInteger,CGFloat;Basic C Primitive Types Are Available in Objective-C
Dot语法是对一个属性的获取方法的封装Objective-C Defines Additional Primitive Types
Bool声明的变量可以去保存一个bool 值,YES or NO;
C Structures Can Hold Primitive Values
NSRange是一个结构体,由location和length构成NSString *mainString = @"this is a long string";
NSRange *subStringRange = [mainString rangeOfsubString:@"long"];
subStringRange = {10,4};index 10从0开始,index 4从1开始,
Objects Can Represent Primitive Values
Strings Are Represented by Instances of the NSString Class
Format Strings Are Used to Build Strings from Other Objects or Values
Numbers Are Represented by Instances of the NSNumber Class
Represent Other Values Using Instances of the NSValue Class
NSNumber类是NSValue类的子类Most Collections Are Objects
Collections如NSArray,NSDictionary等,这些类是用作管理对象的,所以放在这些类中的item必须是class的实例如果需要向collection中添加一个标量值,需要把这个标量值先转化为NSValue或NSNumber对象
在collection中的每一个对象都有一个强的指针去追踪他也就是说添加到collection中的任何对象的生命周期与collection的生命周期一样长
Arrays Are Ordered Collections
NSArray实例中的所有对象都是有序的Creating Arrays
+ arrayWithObject:(id)anObject;+ arrayWithObjects:(id)firstObject, ... ;
+ initWithObjects:(id)firstObject,... ;
arrayWithObjects和initWithObjects都带了一个nil-terminated,也就是说必须包括nil作为最后一个value,nil是一个终结符,告诉array对象到此为止
NSArray *someArray = |
[NSArray arrayWithObjects:someObject, someString, someNumber, someValue, nil]; |
Literal Syntax
NSArray *someArray = @[firstObject, secondObject, thirdObject];如果secondObject=nil,在运行时会出现异常,如果确实需要使得array中的某一个元素值为nil,应用NSNull代替
Querying Array Objects
创建了一个数组之后可以查询数组。例如查询数组中是否有某个item查询数组中元素的个数NSUInteger numberOfItems = [someArray count];
if([someArray containsObject:something]){
}
也能查询数组中某个元素
if([someArray count] >0){
NSLog(@"First Item is %@",[someArray objectAtIndex:0]);
}
Subscripting
if([someArray count] >0){
NSLog(@"First Item is %@",someArray[0]);
}
Sorting Array Objects
NSArray *unsortedStrings = @[@"gammaString", @"alphaString", @"betaString"]; |
NSArray *sortedStrings = |
[unsortedStrings sortedArrayUsingSelector:@selector(compare:)]; |
Mutability
Sets Are Unordered Collections
set与array类似,但是必须是完全不同的对象组成的NSSet也是不可更改的,所以必须在内容必须在创建的时候被指明
NSSet *simpleSet = [NSSet setWithObjects:@"Hello world",@42,aValue,anObject,nil];
initWithObjects和setWithObjects都以nil结束
set中存储的元素不能重复
Dictionaries Collect Key-Value Pairs
Creating Dictionaries
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys: |
someObject, @"anObject", |
@"Hello, World!", @"helloString", |
@42, @"magicNumber", |
someValue, @"aValue", |
nil]; |
dictionaryWithObjectsAndKeys:
and initWithObjectsAndKeys:先指明对象,在指明key,最终以nil标志结束
Literal Syntax
NSDictionary *dictionary = @{ |
@"anObject" : someObject, |
@"helloString" : @"Hello, World!", |
@"magicNumber" : @42, |
@"aValue" : someValue |
}; |
用这种方法创建时key在value前
Querying Dictionaries
创建了一个dictionary之后,可以用被给的key来得到对象
NSNumber *storedNumber = [dictionary objectForKey:@"magicNumber"];如果key没有发现,objectForKey将返回nil
也可以这样访问
NSNumber *storedNumber = dictionary[@"magicNumber"];
Mutability
[dictionary setObject:@"another string" forKey:@"secondString"]; |
[dictionary removeObjectForKey:@"anObject"]; |
Represent nil with NSNull
Use Collections to Persist Your Object Graph
NSArray和NSDictionary对象使得到硬盘上写内容变得容易NSURL *fileURL =
NSArray *array = @[@"first",@"second",@"three"];
Bool success = [array writeToURL:fileURL atomically:YES];
if(!success){
NSLog(@"file write failure");
}
Use the Most Efficient Collection Enumeration Techniques
许多collection采纳了NSFastEnumeration protocol,包括NSArray,NSDictionary,NSSet for (id eachObject in array) { |
NSLog(@"Object: %@", eachObject); |
} |
for (NSString *eachKey in dictionary) { |
id object = dictionary[eachKey]; |
NSLog(@"Object: %@ for key: %@", object, eachKey); |
} |
Most Collections Also Support Enumerator Objects
NSEnumerator
object.
for (id eachObject in [array reverseObjectEnumerator]) { |
... |
} |
六 Working with Blocks
Objective-c 定义了一个可以把数据和行为结合起来的对象,有时候仅仅代表了一个单独的任务,而不是方法的collection
blocks是objective-c的对象,因此就能够添加到collection如NSArray和NSDictionary中
这一小节介绍了block的语法以及怎样用block去处理一个简单的任务
Block Syntax
声明一个变量去追踪block,void (^simpleBlock)(void);
assignment
simpleBlock = ^ {
}
declare and assignment
void (^simpleBlock)(void) = ^{
}
用已经赋值和声明的block变量来激活一个block
simpleBlock ();
用没有赋值的block变量激活block将会使程序崩溃
Blocks Take Arguments and Return Values
block也可以带参数和返回值block变量的声明
double (^multipleTwoValues)(double,double);
block的定义:
^ (double firstValue,double secondValue) {
}
根据喜好也能自己指定返回类型
^ double (double firstValue,double secondValue){
}
一旦声明和定义了一个block就可以像函数一样用它
double (^MultipleTwoValue)(double ,double) = ^(double firstValue,double secondValue) {
return firstValue * secondValue;
}
double result = MultipleTwoValue(2.0,3.0);
在block内可以read block外面定义的变量
block不能改变original variable的值
Use __block Variables to Share Storage
如果你需要在block内部改变在block外部声明的变量的值,可以用__block key words
__block int anInteger = 42; |
|
void (^testBlock)(void) = ^{ |
NSLog(@"Integer is: %i", anInteger); |
}; |
|
anInteger = 84; |
|
testBlock(); |
You Can Pass Blocks as Arguments to Methods or Functions
通常需要把block当成参数传给函数或方法,例如可能需要用Grand Centrol disPatch去在后台激活一个block,或者让block通过不断的激活去完成一个任务,例如collection的枚举当某个任务完成时,让block去执行内部的代码,
在一个方法中把block当作一个参数
- (IBAction)fetchRemoteInformation:(id)sender { |
[self showProgressIndicator]; |
|
XYZWebTask *task = ... |
|
[task beginTaskWithCallbackBlock:^{ |
[self hideProgressIndicator]; |
}]; |
} |
在方法内部激活block - (void)beginTaskWithCallbackBlock:(void (^)(void))callbackBlock { |
... |
callbackBlock(); |
} |
A Block Should Always Be the Last Argument to a Method
Use Type Definitions to Simplify Block Syntax
为simpleBlock定义一个没有返回值没有参数的类型typedef void void(^XYZSimpleBlock)(void)
Objects Use Properties to Keep Track of Blocks
@interface XYZObject : NSObject |
@property (copy) void (^blockProperty)(void); |
@end |
self.blockProperty = ^{ |
... |
}; |
self.blockProperty(); |
typedef void (^XYZSimpleBlock)(void); |
|
@interface XYZObject : NSObject |
@property (copy) XYZSimpleBlock blockProperty; |
@end |
Avoid Strong Reference Cycles when Capturing self
当你在block中用到self是,要考虑避免memory cycle在block内部被用到的所有的对象都有一个strong reference指向他
- (void)configureBlock { |
XYZBlockKeeper * __weak weakSelf = self; |
self.block = ^{ |
[weakSelf doSomething]; // capture the weak reference |
// to avoid the reference cycle |
} |
} |
在block内部用到self时,用weakSelf代替self,__weak关键字紧邻变量名
XYZBlockKeeper * __weak weakSelf = self;
Blocks Can Simplify Enumeration
[array enumerateObjectsUsingBlock:^ (id obj, NSUInteger idx, BOOL *stop) { |
if (...) { |
*stop = YES; |
} |
}]; |
NSDictionary *dictionary = ... |
[dictionary enumerateKeysAndObjectsUsingBlock:^ (id key, id obj, BOOL *stop) { |
NSLog(@"key: %@, value: %@", key, obj); |
}]; |
This makes it more convenient to enumerate each key-value pair than when using a traditional loop, for example.
Blocks Can Simplify Concurrent Tasks
ios提供了多种技术去并发执行,如 Operation queues and Grand Central Dispatch,Use Block Operations with Operation Queues
An operation queue is the Cocoa and Cocoa Touch approach to task scheduling也可以创建NSOperation的子类去实现更加复杂的任务,也可以用NSBlockOperation去用block创建一个NSOperation 实例
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ |
... |
}]; |
// schedule task on main queue: |
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue]; |
[mainQueue addOperation:operation]; |
|
// schedule task on background queue: |
NSOperationQueue *queue = [[NSOperationQueue alloc] init]; |
[queue addOperation:operation]; |
Schedule Blocks on Dispatch Queues with Grand Central Dispatch
如果你需要预先安排block的执行顺序,可以直接用dispatch queue,dispatch queue是由Grand Central dispatch来控制的You can either create your own dispatch queue or use one of the queues provided automatically by GCD
七 Dealing with Errors
每一个app都会遇见错误,而这些错误不是你能掌控的,比如没有网络所有的error都通过NSError class的实例表现出来
Use NSError for Most Errors
error是不可避免的,你唯一要做的就是当发生错误的时候提供给用户最好的体验比如说从远程服务器上downloading信息,你会发现你至少要实现一个发生错误的方法
例如:NSURLConnectionDelegate protocol 包含了connection:didFailWithError: method
-(void) connection:(NSURLConnection*)connection didFailWithError:(NSError*)error;
如果error发生,the delegate method将提供给你一个NSError对象去描述这个问题
NSError对象包含一个数字代码,domain,description
Some Methods Pass Errors by Reference
- (BOOL)writeToURL:(NSURL *)aURL |
options:(NSDataWritingOptions)mask |
error:(NSError **)errorPtr; |
NSError *anyError; |
BOOL success = [receivedData writeToURL:someLocalFileURL |
options:0 |
error:&anyError]; |
if (!success) { |
NSLog(@"Write failed with error: %@", anyError); |
// present error to user |
} |
Recover if Possible or Display the Error to the User
最好的用户体验就是从错误中恢复出来,例如你在获取远程网页响应的时候,你可能会试着从不同服务器上去获取网页的响应如果不可能从错误中恢复出来,你应该alert users,如果你用cocoa touch,你需要用UIAlertView去显示error
Generating Your Own Errors
在创建你自己的NSError对象之前,需要去创建你自己的error domain
com.companyName.appOrFrameworkName.ErrorDomain同时也需要为你的domain中的每一个error指定一个唯一的代码
NSString *domain = @"com.MyCompany.MyApplication.ErrorDomain"; |
NSString *desc = NSLocalizedString(@"Unable to…", @""); |
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : desc }; |
|
NSError *error = [NSError errorWithDomain:domain |
code:-101 |
userInfo:userInfo]; |
Exceptions Are Used for Programmer Errors
@try { |
// do something that might throw an exception |
} |
@catch (NSException *exception) { |
// deal with the exception |
} |
@finally { |
// optional block of clean-up code |
// executed whether or not an exception occurred |
} |