本随笔系列主要介绍从一个Windows平台从事C#开发到Mac平台苹果开发的一系列感想和体验历程,本系列文章是在起步阶段逐步积累的,希望带给大家更好,更真实的转换历程体验。本文继续上一篇随笔《从C#到Objective-C,循序渐进学习苹果开发(3)--分类(category)和协议Protocal的理解》,继续对比介绍它们两者之间的差异,以便我们从C#阵营过来的人员加深印象,深入了解Objective-C语言的特性。本篇随笔主要针对Objective-C里面的代码块(block)和异常处理概念的理解进行介绍。
1、Object C的代码块(block)
Objective-C的代码块从刚刚学习的时候,感觉有点奇怪,慢慢感觉它在C#里面也有点熟悉,它在Objective-C里面的引入,好像是主要用来解决代码回调和同步调用的问题的,说到这里,如果熟悉C#的特性的,可能会联想到了C#里的Action<T>和Func<T>的概念了吧,没错,他们就是一丘之貉,哈哈。
代码块本质上是和其他变量类似。不同的是,代码块存储的数据是一个函数体。使用代码块是,你可以像调用其他标准函数一样,传入参数数,并得到返回值,字符(^)是代码块的语法标记。
如下面的例子就是一个代码块的定义
void (^simpleBlock)(void) = ^{
NSLog(@"This is a block");
};
定义后,你就可以通过类似函数的方式进行使用了,看了下面的代码是不是感觉很熟悉的样子呢。
simpleBlock();
当然,对于这样的东西,它也是可以接受参数的,即使是多个参数也没问题,这个如果是带参数的,应该就是和C#的Func<T>很相似了,下面是一个两个参数的代码块例子。
double (^multiplyTwoValues)(double, double) =
^(double firstValue, double secondValue) {
return firstValue * secondValue;
}; double result = multiplyTwoValues(,);
这样的代码块,它还可以获取类里面定义的局部变量,但是由于它的特殊性,好像如果不加特殊处理,它获取到的变量或者属性的值,是在它出现的那瞬间的快照。
下面一个例子,很好介绍代码块里面获取内容是快照的现实。
int anInteger = ; void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger);
}; anInteger = ; testBlock();
上面代码块里面,打印出来的值,是42,而非84,因为它在代码块出现的那瞬间,就拿到了局部变量,之后就没有跟随大部队变化了。
那这种方式有无变通的方法,让它可以根据变量的变化而自动变化呢?当然有了,需要特殊处理即可,答案就是使用__block进行标识,它就可以跟随大部队的步伐了。
如果上面的代码块里面变量的定义使用了这个关键字,那么值就似乎84了,如下代码块所示。
__block int anInteger = ; void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger);
}; anInteger = ; testBlock();
这个__block功能很强大,告诉编译器,它可以获取变量的最新值,也可以在代码块里面对值进行修改(危险吗?反正你知道就好)
前面说道了,Objective-C里面的代码块类似c#里面lambda的Action 和 Func 那么举个例子来大致介绍下把。
对比一下下面两组代码,其一是Objective-C的代码块
typedef void (^MethodBlock)(int); - (void) fooWithBlock:(MethodBlock)block
{
int a = ;
block(a);
} - (void) regularFoo
{
[self fooWithBlock:^(int val)
{
NSLog(@"%d", val);
}];
}
接着是C#里面的代码例子,感觉它们很接近吧。在这里,你可能会感叹,编程语言这个世界里,很小,世界都趋向于大同了。
void Foo(Action<int> m)
{
int a = ;
m(a);
} void RegularFoo()
{
Foo(val => // Or: Foo(delegate(int val)
{
Console.WriteLine(val);
});
}
不过代码块的使用,你会慢慢感觉它虽然很强大,但是很多地方也不是很容易理解,毕竟对于我们这些入门没有很深根基的人来说,要慢慢消化。
再来看看下面这个例子代码,这个方法里面的代码块定义,很有意思。
- (void)beginTaskWithCallbackBlock:(void (^)(void))callbackBlock {
...
callbackBlock();
}
再来看看下面这个代码块,你可能会更晕,没事,晕了就对了,说明你是一个正常的人。
void (^(^complexBlock)(void (^)(void)))(void) = ^ (void (^aBlock)(void)) {
...
return ^{
...
};
};
最后记得,如果是一个方法有多个参数,记得把代码块的参数放到最后来定义。
- (void)beginTaskWithName:(NSString *)name completion:(void(^)(void))callback;
至于代码块如何简化同步调用的问题,让给读者自己去了解研究了,我感觉也有点头晕了。哈哈。
2、Object C的错误及异常处理
我们知道,在开发各种应用程序或者系统的时候,错误肯定难以避免,有效处理错误异常就是你一个很有必要的内容。在C#里面,我们如果需要抛出异常,我们使用throw方法进行,所有的错误都以异常对象Exception作为基类进行扩展,包括各种各样的异常对象,而对错误异常的捕捉是通过try {} catch(Exception ex) finally {}这样的代码或者类似处理进行的,对于Objective-C来说,它又是如何处理错误异常的呢?
其实Objective-C对错误处理的机制也差不多,它对异常的支持包括四个编译器指令: @try
, @catch
, @throw
以及 @finally。是不是又一次感觉到语言的大同了,这个东西和C#的处理几乎没有什么差别。
另外Objective-C还引入了一个NSError的东西,这个东西和NSException有什么关系呢?这个东西有点类似于我们在C#开发的时候,增加一个out的输入参数,用来把程序内部的错误信息传递出去,然后交给调用者,让它们爱怎么用就怎么用,反正我处理完成了,有无错误我都告诉你了。由于NSError可以传递的信息比较丰富,一般来说这样对程序的处理也很方便。
如网络连接的异常,你可以通过下面的代码把它传递出来。
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
下面我们来看看一个写文件的错误如何处理的,首先定义一个函数,包含了NSError的参数的,注意一般这个参数是放到最后的,这点好像和我们有些这样处理的C#约定也是一样的。
- (BOOL)writeToURL:(NSURL *)aURL
options:(NSDataWritingOptions)mask
error:(NSError **)errorPtr;
那我们调用这个writeToURL的函数的时候,有错误发生就应该处理,错误发生的时候,它执行完毕了,并且返回一个NO的值
NSError *anyError;
BOOL success = [receivedData writeToURL:someLocalFileURL
options:
error:&anyError];
if (!success) {
NSLog(@"Write failed with error: %@", anyError);
// present error to user
}
为了表示错误的了来源,NSError有一个domain的属性,约定一般以公司的名称(或特别的名称)来进行区分。
com.iqidi.appOrFrameworkName.ErrorDomain
如构造一个NSError的代码大概如下所示。
NSString *domain = @"com.iqidi.MyApplication.ErrorDomain";
NSString *desc = NSLocalizedString(@"Unable to…", @"");
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : desc }; NSError *error = [NSError errorWithDomain:domain
code:-
userInfo:userInfo];
而常规的异常,我们一般还是通过NSException进行处理,异常就是发生问题的时候,停下来第一时间请示如何处理,如果有处理的线路就按照处理的线路进行,否则就一级级往上推了。
它的处理和C#差不多,我们都很熟悉了,代码结构如下所示。
@try {
// code that throws an exception
...
}
@catch (CustomException *ce) { // most specific type
// handle exception ce
...
}
@catch (NSException *ne) { // less specific type
// do whatever recovery is necessary at his level
...
// rethrow the exception so it's handled at a higher level
@throw;
}
@catch (id ue) { // least specific type
// code that handles this exception
...
}
@finally {
// perform tasks necessary whether exception occurred or not
...
}
异常的构造和抛出代码和C#的也很类似
NSException* myException = [NSException
exceptionWithName:@"FileNotFoundException"
reason:@"File Not Found on System"
userInfo:nil];
@throw myException;
如果在处理异常的时候,需要处理一些对象的内存释放,那么一般是把它放到@finally包含的代码块里面。
这个和C#类似,虽然C#不会需要处理内存的释放问题,但是对于一些耗时的操作对象,如Connection,一般最好也放到finally里面确保关闭,处理类似。
- (void)doSomething {
NSMutableArray *anArray = nil;
array = [[NSMutableArray alloc] initWithCapacity:];
@try {
[self doSomethingElse:anArray];
}
@finally {
[anArray release];
}
}
如果要抛出原汁原味的异常,这点也和C#相似,通过@throw;方法即可。
@try {
NSException *e = [NSException
exceptionWithName:@"FileNotFoundException"
reason:@"File Not Found on System"
userInfo:nil];
@throw e;
}
@catch(NSException *e) {
@throw; // rethrows e implicitly
}
看到这里,发现大多数的处理机制和语法使用,和C#并无太多的不同,我们了解就好,具体碰到什么问题,在查看下帮助文档,水来土掩,洗洗睡去吧。
从C#到Objective-C,循序渐进学习苹果开发(4)--代码块(block)和错误异常处理的理解的更多相关文章
-
从C#到Objective-C,循序渐进学习苹果开发(3)--分类(category)和协议Protocal的理解
本随笔系列主要介绍从一个Windows平台从事C#开发到Mac平台苹果开发的一系列感想和体验历程,本系列文章是在起步阶段逐步积累的,希望带给大家更好,更真实的转换历程体验.本文继续上一篇随笔<从 ...
-
从C#到Objective-C,循序渐进学习苹果开发(2)--Objective-C和C#的差异
本随笔系列主要介绍从一个Windows平台从事C#开发到Mac平台开发苹果开发的一系列感想和体验历程,本系列文章是在起步阶段逐步积累的,希望带给大家更好,更真实的转换历程体验. 在上篇<从C#到 ...
-
从C#到Objective-C,循序渐进学习苹果开发(7)--使用FMDB对Sqlite数据库进行操作
本随笔系列主要介绍从一个Windows平台从事C#开发到Mac平台苹果开发的一系列感想和体验历程,本系列文章是在起步阶段逐步积累的,希望带给大家更好,更真实的转换历程体验.本篇主要开始介绍基于XCod ...
-
从C#到Objective-C,循序渐进学习苹果开发(5)--利用XCode来进行IOS的程序开发
本随笔系列主要介绍从一个Windows平台从事C#开发到Mac平台苹果开发的一系列感想和体验历程,本系列文章是在起步阶段逐步积累的,希望带给大家更好,更真实的转换历程体验.前面几篇随笔主要介绍C#和O ...
-
从C#到Objective-C,循序渐进学习苹果开发(1)--准备开发账号和开发环境
本随笔系列主要介绍从一个Windows平台从事C#开发到Mac平台苹果开发的一系列感想和体验历程,本系列文章是在起步阶段逐步积累的,希望带给大家更好,更真实的转换历程体验,因为一旦方方面面都精通了,也 ...
-
从C#到Objective-C,循序渐进学习苹果开发(6)--视图控制器的使用
本随笔系列主要介绍从一个Windows平台从事C#开发到Mac平台苹果开发的一系列感想和体验历程,本系列文章是在起步阶段逐步积累的,希望带给大家更好,更真实的转换历程体验.本篇主要开始介绍基于XCod ...
-
0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁
什么是同步 在上一篇0036 Java学习笔记-多线程-创建线程的三种方式示例代码中,实现Runnable创建多条线程,输出中的结果中会有错误,比如一张票卖了两次,有的票没卖的情况,因为线程对象被多条 ...
-
0023 Java学习笔记-面向对象-初始化代码块
初始化代码块 在18篇-类的基本要素中说到,类的三大成员:成员变量.构造方法.方法,初始化代码块是类的第4个成员 初始化块用于对类或者对象的初始化, 一个类的初始化块可以有0-多个,按先后顺序执行 跟 ...
-
iOS学习之代码块(Block)
代码块(Block) (1)主要作用:将一段代码保存起来,在需要的地方调用即可. (2)全局变量在代码块中的使用: 全局变量可以在代码块中使用,同时也可以被改变,代码片段如下: ;//注意:全局变量 ...
随机推荐
-
WCF学习之旅—第三个示例之三(二十九)
上接WCF学习之旅—第三个示例之一(二十七) WCF学习之旅—第三个示例之二(二十八) 在上一篇文章中我们创建了实体对象与接口协定,在这一篇文章中我们来学习如何创建WCF的服务端代码.具体步骤见下面. ...
-
【转载】经典SQL语句大全
[原文地址]http://www.cnblogs.com/yubinfeng/archive/2010/11/02/1867386.html 一.基础 1.说明:创建数据库CREATE DATABAS ...
-
关于TreeView的选中事件
在使用TreeView的选中事件时,发现,SelectAfter在第一次选中时触发,你再次点击时这个事件并不能引发它.所以找了找,发现有另两种解决办法. 最好的就是使用:NodeMouseClick, ...
-
atan函数与atan2函数
atan函数:传送门. atan2函数:传送门. atan 和 atan2 都是求反正切函数,如:有两个点 point(x1,y1), 和 point(x2,y2); 那么这两个点形成的斜率的角度计算 ...
-
Xmind Pro 3.4.0.201311050558 Xmind 3.4 破解版 Crack
其实就一个附件.某大神那里的下不到了.从这里就好了. 使用方法请参见压缩包~ 如果连接不能用了请及时告知回复.>< 仅适用于与版本号为201311050558的Xmind.当然尊重正版开发 ...
-
WebSQL实例记录
<table id="content"> </table> <br> <input type="button" id= ...
-
机械臂——arduino、marlin固件、printrun软件【转】
最近了解到,在市面上大多数机械臂控制都采用的arduino这个开源硬件来控制的,而我发现既然会单片机,就没有必要采用arduino来控制了,arduino只是一种为了简化编程而开发一种软硬件控制平台, ...
-
性能测试day02_后端网络协议架构
接着第一天的尾,继续来学习性能测试,上一次说到性能要大致经历哪些阶段,那么我们也来看下行业的做法: 行业有两种做法,一个是TPC,另一个是SPEC: TPC:指定业务类型,获得该指定业务的性能指标,也 ...
-
AutoFac实现WebAPI依赖注入(EF以及Mysql)
什么是依赖注入? 我们以实际的例子来加以介绍 实体如下 public class Product { public int ID { get; set; } public string Name { ...
-
Elasticsearch使用BulkProcessor批量插入
https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high-document-bulk. ...