尝试通过函数传递错误时出现错误访问错误

时间:2012-08-10 21:00:20

标签: objective-c nserror

我正在尝试在我的课程中实现一些错误处理。我不认为我对如何处理错误有充分的理解,但我注意到人们建议,将函数中的错误声明为(NSError *__autoreleasing *error)所以我这样做了。我在通过函数传递错误时遇到问题。

发生以下问题: 打破它似乎以下问题:(对不起,实际代码太长但我试图提取最重要的问题!我希望我的代码范围包含问题)

想象一下,您使用 ObjectA 方法:

    -(NSString *) do1: (NSString *) withstuff error:(NSError *__autoreleasing *)error{
         //...
         //error happens
         *error = [[NSError alloc] initwithDomain: domain code: blah userinfo: infodict];
         return nil;
    }
    -(BOOL) do2error:(NSError *__autoreleasing *)error{
         NSString *doesntmatter = [self do1: @"whatever" error: error];
         if (doesntmatter == nil){
              return NO;
         }
    }

现在在另一个类(AppDelegate对象)中,我调用以下内容:

       ObjectA* ob1 = [[ob1 alloc] init];
       NSError *errorBoom = nil;
       if ([ob1 do2error:&errorBoom] == NO){
            NSLog(@"error: %@",errorBoom); //---> bad access error 
       }

看起来似乎不再可以访问errorBoom了?是因为“__autoreleasing”,我试图理解它实际意味着什么,但到目前为止所有的解释对我来说都不是很有用,因为我在这个领域很新......我希望你能帮助我!

修改

好的,我想我已经找到了错误。现在我知道是什么导致了它,但我不知道为什么。我写了一个简单的示例应用程序,它提取“错误访问” - 错误发生的主要来源:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions (NSDictionary *)launchOptions
    {
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        // Override point for customization after application launch.
        NSError *errtest = nil;
        BOOL testBool = [self messaroundwitherr:&errtest];
        NSLog(@"Filled NSError? : %@",errtest); //<--Causes Bad Access.

        self.window.backgroundColor = [UIColor whiteColor];
        [self.window makeKeyAndVisible];
        return YES;
    } 
    -(BOOL) giveErrornow:(NSError *__autoreleasing *)err {
        NSMutableDictionary *errInfo = [[NSMutableDictionary alloc] init];
        [errInfo setObject:@"I feel like giving you an error!" forKey:NSLocalizedDescriptionKey];
        *err = [[NSError alloc] initWithDomain:@"nonesense"
                                  code:0
                              userInfo:errInfo];
        return  NO;
    }
    -(BOOL) messaroundwitherr:(NSError *__autoreleasing *)err{
        //@autoreleasepool { --> uncommenting that causes the error
            return [self giveErrornow: err];
        //}
    }

显然激活autoreleasepool,使得err变量在被外部函数(AppFinishLaunching ...)读取之前就被释放了。现在为什么会发生这种情况呢?我知道“@autoreleasepool”在使用后释放变量。在原始的上下文中,我有一个while循环,这就是我这样做的原因。这只是出于理解的原因。 那么@“autoreleasepool”如何运作?实际上命令会发生什么(* __ autorelease *)。

我想在修复之前我必须完全理解它的概念。 NSError(* __ autorelease *)错误是否为ARC定义了一个“指向要自动释放的对象的指针(如果是,何时)”的指针?

2 个答案:

答案 0 :(得分:2)

好的,我想在两个有用的网站的帮助下弄明白了:

http://blog.pioneeringsoftware.co.uk/2012/03/06/out-parameters-when-arcing

http://openbook.galileocomputing.de/apps_entwickeln_fuer_iphone_und_ipad/apps_02_005.html#dodtpc7187bdd-6422-4c4f-92d2-c60983032cf5

(不幸的是,第二个是德语: - ))

无论如何,基本概念如下:

  1. 通过引用定义变量,如:

        (NSError ** err) or (NSError *__autoreleasing * err) 
    

    始终让ARC将其重写为:

        (NSError *__autoreleasing * err)
    

    并重写

         *err = [[NSError alloc] initWithDomain:@"nonesense"
                              code:0
                          userInfo:errInfo]
    

         *err = .....]retain] autorelease];
    

    所以错误对象被标记为autorelease。

  2. 现在正如文档中所述:

      

    在自动释放池块的末尾,在块中接收到自动释放消息的对象被发送释放消息 - 对象在块中发送自动释放消息时接收释放消息

  3. 所以从1和2基本上发生的是,当取消注释@autoreleasepool块时,错误正在

    中创建
        giveErrornow:(NSError *__autoreleasing *)err 
    

    函数,从autoreleasepool中调用,因此* errtest在被用于

    之前被释放和释放
        NSLog(@"Filled NSError? : %@",errtest)
    

    是的,所以基本上就是这样。在处理参数时似乎是一个普遍问题,并且可以更改有问题的代码,例如:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions (NSDictionary *)launchOptions
    {
        self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        // Override point for customization after application launch.
        NSError *errtest = nil;
        BOOL testBool = [self messaroundwitherr:&errtest];
        NSLog(@"Filled NSError? : %@",errtest); //<--Causes Bad Access.
    
        self.window.backgroundColor = [UIColor whiteColor];
        [self.window makeKeyAndVisible];
        return YES;
    } 
    -(BOOL) giveErrornow:(NSError *__autoreleasing *)err {
        NSMutableDictionary *errInfo = [[NSMutableDictionary alloc] init];
        [errInfo setObject:@"I feel like giving you an error!" forKey:NSLocalizedDescriptionKey];
        *err = [[NSError alloc] initWithDomain:@"nonesense"
                                  code:0
                              userInfo:errInfo];
        return  NO;
    }
    -(BOOL) messaroundwitherr:(NSError *__autoreleasing *)err{
        NSError *tempErr;
        BOOL retVal;
        @autoreleasepool {
            retVal = [self giveErrornow:&tempErr];
        }
        *err = tempErr;
        return retVal;
    }
    

    欢迎您留下任何有关此问题的评论。如果我能正确理解问题,我会感到很高兴。

答案 1 :(得分:1)

最后,我能够找出原因并加以解决。就我而言,在 autorelease 块内分配的AndyApp.template对象被释放,这导致崩溃。我已经创建了一个error(NSError)对象的副本,并将其分配给了外部代码块,它解决了我的问题。

NSError
相关问题