【问题标题】:Defining a method that returns an error定义返回错误的方法
【发布时间】:2013-10-06 21:38:25
【问题描述】:

如何定义一个既返回错误又返回值的方法?

例如,当我调用 managedObjectContext 保存方法时,该方法返回一个布尔值,以及一个错误:

if(![context save:&error]) {
    NSLog(@"%@", error);
}

你能给我一个简单的例子来说明这背后的方法定义吗?

编辑/更新:在同样的方面,怎么可能传回多个错误。我在下面做错了(我可能还不明白这个概念),这不起作用:

NSArray *errors = nil;
[self throwMultipleErrors:&errors];
for(id error in errors) {
    NSLog(@"Muliple error: %@", error);
}...

-(BOOL)throwMultipleErrors:(NSMutableArray **) errors {
    [*errors addObject:@"First Error"];
    [*errors addObject:@"Second Error"];
    [*errors addObject:@"Third Error"];

    return YES;
}

【问题讨论】:

  • 没关系,我忘了通过将数组指向 nil 来实例化数组:\
  • 不要以NSMutableArray** 的身份传递信息。使用NSError** 并将您的多个子错误放入用户信息字典中。

标签: objective-c out-parameters


【解决方案1】:

在您的示例中,方法签名是:

- (BOOL)save:(NSError **)error;

这允许调用者将NSError 作为地址而不是指针(指向指针的指针,**&)传递,然后该方法可以从另一个范围分配。如果该方法返回 false,则调用者可以检查错误变量的内容,如您的示例所示。

有关在变量前使用&(NSError **) 签名的更多信息,请参阅此问题。

Why is `&` (ampersand) put in front of some method parameters?

示例实现:

    - (BOOL)save:(NSError **)error
    {
       NSAssert(error != nil, @"Passed NSError must be nil!");
       // Attempt to do a save
       if (saveDidFail) {
             NSDictionary *userInfo = [NSDictionary dictionaryWithObjectAndKeys:@"Save Failed", kCustomErrorKey, nil];
             *error = [NSError errorWithDomain:@"domain" code:999 userInfo:userInfo];
             return NO;
       } 
       return YES;
    }

【讨论】:

  • 你能告诉我如何在方法中处理错误吗?
  • 谢谢蒂姆!抱歉,再向前一步,我想知道是否可以传回一系列错误?我知道这需要传入类似 -(BOOL)save:(NSMutableArray **) 错误
  • 你可以这样做,但我不确定你为什么需要这样做?你不能在 NSError 的 userInfo 部分回传更多信息吗?但是,是的,(NSMutableArray **)errors,就是你要做的。
  • 将多个错误放入用户信息字典; '工具包在不同的地方这样做。请注意,上面的代码在设置 `*error* 之前缺少if(error)
  • 它还缺少检查 *error 是否尚未设置,如果调用者传入已分配对象的值,则会导致潜在的内存管理错误。
【解决方案2】:

使用您的示例,方法签名将是:

-(BOOL)save:(NSError**)error;

现在,在使用双指针时,您需要在编程中采取防御措施。首先,您必须确保error 的值不是nil,然后*errornil。您必须这样做,因为您不知道如何对现有对象进行明智的内存管理。例如:

NSError *error = nil;
[self save:&error];

应该是正确的。但是

NSError *error = [[NSError alloc] init];
[self save:&error];

是一个问题,因为如果errorretainedautoreleased,您的save: 方法将不会出现。如果你release 它是autoreleased,那么你的应用程序最终会崩溃。相反,如果你不release 它是retained 你会泄漏内存。我建议使用断言检查此问题,以便在签入代码之前快速解决问题。

NSAssert(!error || !*error, @"*error must be nil!");

最后,在设置*error 时,您必须确保error 不是nil。您永远不能设置内存地址0x0 的值。如果您不检查并且将nil 传递给该方法,那么如果您尝试设置它,您将会崩溃。

if (error)
{
    *error = [NSError ...];
    return NO;
}

要返回一个数组,我会这样做:

-(BOOL)throwMultipleErrors:(NSError **) error {

    NSAssert(!error | !*error, @"*error must be nil");

    NSMutableArray *errorList = nil;

    if (error)
        errorList = [NSMutableArray array];


    [errorList addObject:@"First Error"];
    [errorList addObject:@"Second Error"];
    [errorList addObject:@"Third Error"];

    if (error && [errorList count] > 0)
    {
        *error = [NSError errorWithDomain:@"Some error"
                                     code:0
                                 userInfo:@{@"suberrors" : [NSArray arrayWithArray:errorList]}];
        return NO;
    }

    return YES;
}

请注意,返回数组是不可变的,并在方法内部实例化。这个数组真的没有理由在这个方法之外是可变的,也没有理由在它之外实例化数组。将数组封装在 NSError 中可以轻松适应现有的 NSError 方法链。

注意事项

当然,您实际上会将[self save:&error]; 调用放入if() 语句中以检查返回值。但是请注意,我们传递的是&error 而不仅仅是error。这是因为我们需要将 指针 传递给error,而不是error 本身。 &error 读作“错误地址”。

【讨论】:

  • 感谢 berquester!你能帮我看看更新的问题,并告诉我当我想传回一系列错误时我做错了什么吗?
  • 是的,我可以,但首先我有一个问题。为什么需要返回多个错误?为什么不在第一个错误时退出?这通常是这些事情的处理方式。
  • 没关系,我忘了实例化数组。所以基本上我正在调用多种方法来传回它们自己的错误。例如,我有一个函数(registerUSer),它包含保存到数据库(可能返回错误)以及保存核心数据(可能返回第二个错误)。我希望 registerUser 返回一个错误数组。
  • 创建了一个返回数组的防御版本。
  • @BergQuester 更好的解决方案是使用通用封装NSError,其用户信息字典包含suberrors 数组。
【解决方案3】:

我们需要注意这里的语法。 当我们将 NSError 传递给方法时: + (instancetype)stringWithContentsOfFile:(NSString *)路径编码:(NSStringEncoding)enc 错误:(NSError * *)error

我们将句柄(指向指针的指针)交给尚未初始化的错误对象。如果被调用的消息遇到问题,它将初始化并填充错误对象。它不会“返回”错误,只需将值填充到传递的参数中即可。

所以如果我想定义一个返回值的消息,并且还需要一个错误参数,请按照本教程进行操作: http://www.cimgf.com/2008/04/04/cocoa-tutorial-using-nserror-to-great-effect/

【讨论】:

  • 你的方法签名不正确,应该是(NSError **)error
猜你喜欢
  • 2013-01-12
  • 1970-01-01
  • 2014-04-10
  • 2021-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-26
  • 1970-01-01
相关资源
最近更新 更多