在objective-c / cocoa中抛出异常的最佳方法是什么?


#1楼

使用NSError来传达故障而不是异常。

关于NSError的快速点:

  • NSError允许C样式错误代码(整数)清楚地标识根本原因,并希望允许错误处理程序克服错误。 您可以非常轻松地在NSError实例中包含SQL库(如SQLite)中的错误代码。

  • NSError还具有作为对象的优点,并提供了一种使用其userInfo字典成员更详细地描述错误的方法。

  • 但最重要的是,不能抛出NSError,因此它鼓励采用更主动的错误处理方法,与其他语言相比,这些语言只是将热门土豆进一步向上调整堆栈,此时它只能报告给用户和没有以任何有意义的方式处理(如果你相信遵守OOP隐藏的最大信息原则)。

参考链接: 参考


#2楼

我没有代表对eJames的回应发表评论,所以我想我需要把它放在这里。 对于那些来自Java背景的人,您会记得Java区分Exception和RuntimeException。 异常是已检查的异常,并且未选中RuntimeException。 特别是,Java建议使用“正常错误条件”的已检查异常和“由程序员错误导致的运行时错误”的未经检查的异常。 似乎应该在使用未经检查的异常的相同位置使用Objective-C异常,并且在使用已检查异常的位置首选错误代码返回值或NSError值。


#3楼

我相信你永远不应该使用Exceptions来控制正常的程序流程。 但是,只要某些值与期望值不匹配,就应该抛出异常。

例如,如果某个函数接受一个值,并且该值永远不允许为零,则可以设置异常,而不是尝试做一些“聪明”的事情......

里斯


#4楼

您可以使用两种方法在try catch块中引发异常

@throw[NSException exceptionWithName];

或第二种方法

NSException e;
[e raise];

#5楼

从ObjC 2.0开始,Objective-C异常不再是C的setjmp()longjmp()的包装器,并且与C ++异常兼容,@ try是“免费的”,但抛出和捕获异常的方式更为昂贵。

无论如何,断言(使用NSAssert和NSCAssert宏系列)抛出NSException,并且理所当然地将它们用作Ries状态。


#6楼

这就是我从“The Big Nerd Ranch Guide(第4版)”中学到的:

@throw [NSException exceptionWithName:@"Something is not right exception"reason:@"Can't perform this operation because of this or that"userInfo:nil];

#7楼

如果您发现自己处于指示编程错误的情况并且想要停止运行应用程序,则应该只抛出异常。 因此,抛出异常的最佳方法是使用NSAssert和NSParameterAssert宏,并确保未定义NS_BLOCK_ASSERTIONS。


#8楼

我使用[NSException raise:format:]如下:

[NSException raise:@"Invalid foo value" format:@"foo of %d is invalid", foo];

#9楼

@throw([NSException exceptionWith…])

#10楼

我认为是一致的,使用@throw与你自己的类扩展NSException更好。 然后你最后使用相同的符号来try catch:

@try {
.....
}
@catch{
...
}
@finally{
...
}

Apple在这里解释了如何抛出和处理异常: 捕获异常 抛出异常


#11楼

这里要谨慎。 在Objective-C中,与许多类似的语言不同,您通常应该尽量避免对正常操作中可能发生的常见错误情况使用异常。

Apple的Obj-C 2.0文档声明如下:“重要:在Objective-C中,异常是资源密集型的。您不应该使用异常进行常规流量控制,或者只是表示错误(例如文件无法访问)”

Apple的概念异常处理文档解释相同,但更多的话:“重要:您应该保留使用异常编程或意外的运行时错误,例如越界集合访问,尝试改变不可变对象,发送无效消息并且失去了与窗口服务器的连接。在创建应用程序时而不是在运行时,通常会处理这些类型的错误和异常。[......]而不是异常,错误对象(NSError)和Cocoa错误传递机制是在Cocoa应用程序中传达预期错误的推荐方法。“

其原因部分是为了坚持Objective-C中的编程习惯用法(在更复杂的情况下使用简单情况下的返回值和引用参数(通常是NSError类)),部分原因是抛出和捕获异常要贵得多,最后(并且最重要的是),Objective-C异常是C的setjmp()和longjmp()函数的一个薄包装,基本上搞乱了你仔细的内存处理,请参阅这个解释 。


#12楼

没有理由不在目标C中正常使用例外来表示业务规则例外。 Apple可以说使用NSError谁在乎。 Obj C已经存在了很长时间,同时所有C ++文档也说了同样的话。 抛出和捕获异常的成本并不重要的原因是,异常的生命周期非常短......并且它是正常流程的例外。 在我的生命中,我从来没有听过任何人说过,那个例外需要很长时间才能被抛出并被抓住。

此外,有些人认为目标C本身太昂贵,而且用C或C ++编写代码。 所以说永远使用NSError是不明智和偏执的。

但是这个问题的问题还没有得到解决,这是抛出异常的最好方法。 返回NSError的方法很明显。

所以它是:[NSException raise:... @throw [[NSException alloc] initWithName ....或@throw [[MyCustomException ...?

我在这里使用选中/未选中的规则与上面略有不同。

选中/取消选中(使用java隐喻)之间的真正区别很重要 - >是否可以从异常中恢复。 通过恢复我的意思不仅仅是不崩溃。

所以我使用@throw的自定义异常类来获取可恢复的异常,因为我可能会有一些app方法在多个@catch块中查找某些类型的失败。 例如,如果我的应用程序是ATM机,我将有一个@catch块用于“WithdrawalRequestExceedsBalanceException”。

我使用NSException:引发运行时异常,因为我无法从异常中恢复,除了在更高级别捕获并记录它。 并且没有必要为此创建自定义类。

无论如何,这就是我所做的,但如果有一种更好的,同样富有表现力的方式,我也想知道。 在我自己的代码中,由于我很久以前就停止编写C hella,即使我通过API传递了一个NSError,也永远不会返回NSError。


#13楼

案例的示例代码:@throw([NSException exceptionWithName:...

- (void)parseError:(NSError *)errorcompletionBlock:(void (^)(NSString *error))completionBlock {NSString *resultString = [NSString new];@try {NSData *errorData = [NSData dataWithData:error.userInfo[@"SomeKeyForData"]];if(!errorData.bytes) {@throw([NSException exceptionWithName:@"<Set Yours exc. name: > Test Exc" reason:@"<Describe reason: > Doesn't contain data" userInfo:nil]);}NSDictionary *dictFromData = [NSJSONSerialization JSONObjectWithData:errorDataoptions:NSJSONReadingAllowFragmentserror:&error];resultString = dictFromData[@"someKey"];...} @catch (NSException *exception) {NSLog( @"Caught Exception Name: %@", exception.name);NSLog( @"Caught Exception Reason: %@", exception.reason );resultString = exception.reason;} @finally {completionBlock(resultString);
}

}

使用:

[self parseError:error completionBlock:^(NSString *error) {NSLog(@"%@", error);}];

另一个更高级的用例:

- (void)parseError:(NSError *)error completionBlock:(void (^)(NSString *error))completionBlock {NSString *resultString = [NSString new];NSException* customNilException = [NSException exceptionWithName:@"NilException"reason:@"object is nil"userInfo:nil];NSException* customNotNumberException = [NSException exceptionWithName:@"NotNumberException"reason:@"object is not a NSNumber"userInfo:nil];@try {NSData *errorData = [NSData dataWithData:error.userInfo[@"SomeKeyForData"]];if(!errorData.bytes) {@throw([NSException exceptionWithName:@"<Set Yours exc. name: > Test Exc" reason:@"<Describe reason: > Doesn't contain data" userInfo:nil]);}NSDictionary *dictFromData = [NSJSONSerialization JSONObjectWithData:errorDataoptions:NSJSONReadingAllowFragmentserror:&error];NSArray * array = dictFromData[@"someArrayKey"];for (NSInteger i=0; i < array.count; i++) {id resultString = array[i];if (![resultString isKindOfClass:NSNumber.class]) {[customNotNumberException raise]; // <====== HERE is just the same as: @throw customNotNumberException;break;} else if (!resultString){@throw customNilException;        // <======break;}}} @catch (SomeCustomException * sce) {// most specific type// handle exception ce//...
} @catch (CustomException * ce) {// most specific type// handle exception ce//...
} @catch (NSException *exception) {// less specific type// do whatever recovery is necessary at his level//...// rethrow the exception so it's handled at a higher level@throw (SomeCustomException * customException);} @finally {// perform tasks necessary whether exception occurred or not}

}

在objective-c / cocoa中抛出异常相关推荐

  1. 1.1 objective-c中的内存管理

    备注:本来在一年前有一个出版社找到我,让我写一系列关于iOS性能优化的书.但是一直因为工作原因,没有能够按时交付.(其实就是自己懒)所以现在讲已经写好的部分章节分享到博客中,希望对大家有所帮助,如果有 ...

  2. oracle 游标中抛出异常的处理方式

    在oracle游标的使用中,用for循环是一种较直接open 游标然后关闭游标更好的应用方式.现在写两个存储过程,验证这两种情况下游标中抛出异常后游标是否正常关闭. 现在有一张表emp,表结构如下: ...

  3. 构造函数和析构函数中抛出异常

    文章目录 1 构造函数中抛出异常 2 析构函数中的异常 1 构造函数中抛出异常 如果构造函数中抛出异常会发生什么情况? 构造函数中抛出异常: 构造过程立即停止. 当前对象无法生成. 析构函数不会被调用 ...

  4. 27.能否在构造函数中抛出异常?析构函数呢?

    首先,我们要明确一点!一个函数执行的过程中,如果抛出异常,会导致函数提前终止! 在C++构造函数中,既需要分配内存,又需要抛出异常时要特别注意防止内存泄露的情况发生.因为在构造函数中抛出异常,在概念上 ...

  5. java中主函数抛出的异常怎么解决_java – 从递归函数中抛出异常

    我为一个更大的应用程序构建了一个库/模块,它从函数中抛出异常.如果找不到文件或文件包含错误格式,则抛出Exeption. 该方法看起来像: Shape parse(String path) throw ...

  6. java8 foreach 异常_错误处理 – 在java 8流foreach中抛出异常

    我正在使用 java 8流,我不能在流的foreach中抛出异常. stream.forEach(m -> { try { if (isInitial) { isInitial = false; ...

  7. Jvm处理Java Thread 的run方法中抛出异常的流程

    Jvm处理Java Thread 的run方法中抛出异常的流程 参考文章: (1)Jvm处理Java Thread 的run方法中抛出异常的流程 (2)https://www.cnblogs.com/ ...

  8. java catch 抛出异常_java - 在catch和最后claus中抛出异常

    java - 在catch和最后claus中抛出异常 关于大学的Java问题,有这段代码: class MyExc1 extends Exception {} class MyExc2 extends ...

  9. php try 中 抛出异常处理,php中try catch捕获异常实例详解

    php中try catch可以帮助我们捕获程序代码的异常了,这样我们可以很好的处理一些不必要的错误了,感兴趣的朋友可以一起来看看. PHP中try{}catch{}语句概述 PHP5添加了类似于其它语 ...

最新文章

  1. shell脚本输出菱形与等边三角形
  2. 你在做大数据?你有目标么?
  3. echarts指针进度条刻度调整_指针式流量开关
  4. Laravel 5.2问题-----postman进api的post请求,为什么出现Forbidden?
  5. 35款非常有创意的透明名片设计作品
  6. cuSPARSE库:(十)cusparseCreateMatDescr()
  7. 逻辑SQL Server数据复制101
  8. PyCharm 默认运行 unittest
  9. JavaWeb实现简易新闻管理系统
  10. 模式识别与机器学习第四章特征选择和提取
  11. 华为路由器远程登陆之ssh
  12. Hark的数据结构与算法练习之若领图排序ProxymapSort
  13. 【初创公司系列】由软件先驱Tom Siebel支持的机器学习创业公司C3.ai申请IPO
  14. Mysql 2003错误 10038 1045 (推荐第七次解决方案)
  15. 数据分析师常用的十种数据分析思路
  16. FTP服务器文件自动上传、下载(bat)
  17. 转稚晖军大佬 --【自制FOC驱动器】深入浅出讲解FOC算法与SVPWM技术
  18. 解决Anaconda 安装创建菜单失败问题
  19. Unity3D崩溃没保存怎么办
  20. Fiddler:Fiddler新旧版抓包相关总结

热门文章

  1. 把windows一个目录mount到Ubuntu下,非root用户没有写权限
  2. build.gradle
  3. percona mysql安装_mysql 安装 (percona)
  4. Flutter开发之爬坑集合(五)
  5. Spring Boot 小技巧
  6. Python2和Python3关于reload()用法的区别
  7. alert(1) to win 16
  8. Git 中.gitignore 使用和.gitignore 无效的解决方法
  9. 字符编码的发展(ASCII、Unicode、utf-8)
  10. node 关键点总结