在 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 中详细介绍

在 Objective-C 中使用数组试图简化大量重复代码

Objective-C中的原子属性与线程安全

从 Objective-C 调用 Python 代码

不兼容的 Objective-C 类型 - 试图传递 NSURL

应用程序试图在 React Native Objective-C 扩展中的目标上呈现一个 nil 模态视图控制器