在 Objective-C 中,我试图封装多个可出错的调用并“返回”最有用的错误
Posted
技术标签:
【中文标题】在 Objective-C 中,我试图封装多个可出错的调用并“返回”最有用的错误【英文标题】:In Objective-C, I'm trying to encapsulate multiple error-able calls and "return" the most useful error 【发布时间】:2010-05-25 20:31:35 【问题描述】:我将“return”放在引号中,因为我不想按字面意思返回它。我想这样做类似于您为[NSString stringWithContentsOfFile:usedEncoding:error:]
传递一个指向指针的指针。
我想让parseFiles:error
返回 nil 并让传入的错误引用包含第一个或第二个错误,具体取决于哪个错误。这似乎是 Cocoa 的做法?
编辑:对不起,我应该更清楚我在哪里遇到了问题。如果第一条路径是虚假的,它会按我的意愿运行。 (我在外面得到错误实例并打印出来。)如果第一个路径是合法的,正如下面的填充字符串所暗示的那样,我得到EXC_BAD_ACCESS
。
但现在我修好了。我需要在parseFiles:error:
方法中将其称为*error
,并在检查它是否失败时使用== nil
。我以为我可以直接if (error)
...
编辑 2 好的,它不起作用。我收到EXC_BAD_ACCESS
。我不确定我在检查错误的条件下做错了什么。
@implementation PassingError
- (id)init
self = [super init];
NSError *error;
[self parseFiles:@"/untitled.py" error:&error];
if (error != nil)
NSLog(@"I failed because: %@", error);
return self;
// Wraps with reading errors.
- (NSString *)parseFiles:(NSString *)path error:(NSError **)error
NSStringEncoding enc1;
NSString *contents1 = [NSString stringWithContentsOfFile:path
usedEncoding:&enc1 error:*&error];
// there was a read error
// I need an asterisk here...
if (*error != nil)
// ...and also one here
NSLog(@"FIRST ERROR: %@", *error);
return nil;
// here is where you'd do something that might cause another error,
// I'll just try and read a second file for simplicity
NSStringEncoding enc2;
NSString *contents2 = [NSString stringWithContentsOfFile:@"/untitled.py"
usedEncoding:&enc2 error:*&error];
// there was a SECOND error
if (*error != nil)
NSLog(@"SECOND ERROR: %@", *error);
return nil;
// return both or whatever
return [NSArray arrayWithObjects:contents1, contents2, nil];
@end
【问题讨论】:
如果第一次调用返回错误,您将从方法返回,因此您永远不需要返回两个对象。另外,*&
的东西是怎么回事?
我以为我在那里遇到了 EXC_BAD_ACCESS 错误,并且修复了它,但我逐步检查并发现问题出在其他地方。我编辑了代码以删除那些东西。另外,我并不是说我想返回两个对象,我只是想访问相关的错误。这主要是一个指针语法问题。
但是您的代码已经这样做了...
它没有用,我的修复也没有。当我检查第一个错误时,我不确定我应该在语法上做什么。应该是if(*error)
还是if(&error)
还是if(*error != nil)
等等...
你应该首先确保error
是一个指向指针的非空指针,否则你可能会取消引用NULL
。
【参考方案1】:
在 Objective-C 中传递指针会让人感到困惑。我记得很难掌握需要做的事情。当你有这样的方法时:
- (BOOL) saveValuesAndReturnError:(NSError **) error
BOOL success = [self doSomethingImportant];
if (!success && error)
// Unsuccessful and error is a valid ptr-to-ptr-to-NSError.
// Basically, someone has given us the address of a (NSError *).
// We can modify what that pointer points to here.
*error = [NSError errorWithDomain:@"myDomain" code:100 userInfo:nil];
return success;
这是打算这样调用的:
// If the caller doesn't care that it failed:
[someObject saveValuesAndReturnError:NULL];
// Or, if the caller wants to get error information on failure
NSError *anError = nil;
BOOL success;
// pass address of our (NSError *)
success = [someObject saveValuesAndReturnError:&anError];
if (!success)
// anError now points to an NSError object, despite being initialised to nil,
// because we passed the address of our NSError ptr, the method was able to
// change where `anError` points to.
NSLog (@"An error occurred while saving values: %@", anError);
也许在这种情况下,一个非常相关的阅读是 CIMGF blog post 完全涵盖了这个主题。
但是...
我记得前段时间读到,通过方法参数(例如stringWithContentsOfFile:usedEncoding:error:
)返回错误的方法不能保证不修改错误参数以取得成功。换句话说,如果方法成功,您不能依赖错误参数的值。在您的特定情况下,最好这样做:
- (NSString *)parseFiles:(NSString *)path error:(NSError **)error
NSStringEncoding enc1, enc2;
NSError *innerError;
NSString *contents1 = [NSString stringWithContentsOfFile:path
usedEncoding:&enc1
error:&innerError];
if (contents1 == nil)
if (error) *error = innerError;
return nil;
NSString *contents2 = [NSString stringWithContentsOfFile:@"/untitled.py"
usedEncoding:&enc2
error:&innerError];
if (contents2 == nil)
if (error) *error = innerError;
return nil;
// do whatever with contents1 and contents2
【讨论】:
感谢您的详细回答和链接! 是否应该在两次调用之间将 innerError 重置为零?你说你不能确定它没有在 content1 调用中被修改,你能确定 content2 调用覆盖吗? @zekel:是的,您可以将其设置为nil
以确保安全,但我认为目前这不是必需的。 error
参数是一个 output 参数,所以理论上它不应该依赖于它给出的任何输入值(我想不出任何理由让它尝试读取给定的指针) ,但谁知道呢!谨慎行事总比后悔好。以上是关于在 Objective-C 中,我试图封装多个可出错的调用并“返回”最有用的错误的主要内容,如果未能解决你的问题,请参考以下文章
XCode TableViewController 在 Objective-C 中详细介绍