3

使用 ARC,以下示例都有内存泄漏,因为引发了具有动态内容的异常。动态内容没有发布也就不足为奇了,因为异常阻止了函数的正常返回。这些内存泄漏确实不是一个大问题,因为应该谨慎使用异常,例如当应用程序失败而没有恢复机会时。我只是想确保没有某种方法可以释放我目前不知道的内存。


- (void)throwsException
{
    NSString *dynamicContent = [NSString stringWithFormat:@"random value[%d]", arc4random() % 100];
    [NSException raise:@"Some random thing" format:@"%@", dynamicContent];
}

以下两个示例使用上述方法throwsException抛出异常,以使示例不那么做作。

- (void)test_throwsException_woAutoreleasepool
{
    @try
    {
        [self throwsException];
        NSLog(@"No exception raised.");
    }
    @catch (NSException *exception)
    {
        NSLog(@"%@ - %@", [exception name], [exception reason]);
    }
}

注意使用@autoreleasepool,仍然有内存泄漏。

- (void)test_throwsException_wAutoreleasepool
{
    @autoreleasepool {
        @try
        {
            [self throwsException];
            NSLog(@"No exception raised.");
        }
        @catch (NSException *exception)
        {
            NSLog(@"%@ - %@", [exception name], [exception reason]);
        }
    }
}

try与上面的示例相同,只是通过直接在块中引发异常更加人为。

- (void)test_consolidated_raiseFormat
{
    @autoreleasepool {
        @try
        {
            NSString *dynamicContent = [NSString stringWithFormat:@"random value[%d]", arc4random() % 100];
            [NSException raise:@"Some random thing" format:@"%@", dynamicContent];
            NSLog(@"No exception raised.");
        }
        @catch (NSException *exception)
        {
            NSLog(@"%@ - %@", [exception name], [exception reason]);
        }
    }
}

此示例使用exceptionWithName. 没有预期的差异。

- (void)test_consolidated_exceptionWithName
{
    @autoreleasepool {
        @try
        {
            NSString *dynamicContent = [NSString stringWithFormat:@"random value[%d]", arc4random() % 100];
            NSException *exception = [NSException exceptionWithName:@"Some random thing"
                                                             reason:dynamicContent
                                                           userInfo:nil];
            [exception raise];
            NSLog(@"No exception raised.");
        }
        @catch (NSException *exception)
        {
            NSLog(@"%@ - %@", [exception name], [exception reason]);
        }
    }
}

此示例使用initWithName. 没有预期的差异。

- (void)test_consolidated_initWithName
{
    @autoreleasepool {
        @try
        {
            NSString *dynamicContent = [NSString stringWithFormat:@"random value[%d]", arc4random() % 100];
            NSException *exception = [[NSException alloc] initWithName:@"Some random thing"
                                                                reason:dynamicContent
                                                              userInfo:nil];
            [exception raise];
            NSLog(@"No exception raised.");
        }
        @catch (NSException *exception)
        {
            NSLog(@"%@ - %@", [exception name], [exception reason]);
        }
    }
}
4

1 回答 1

0

看起来 NSException 从根本上与 ARC 不兼容。出于同样的原因,从这些异常没有在 Swift 中实现的事实来看。我很想知道为什么您认为泄漏是通过将项目附加到异常来触发的,而不是在引发事件之前仅保留计数为“1”。

想想看 - NSException 是一个对象,它的选择器可以动态传递,所以编译器将“raise”解释为语言特性事件是不对的。因此,在该特定位置没有添加任何 ARC 释放指令。

更新 - 这是另一种解释

为什么 Objective-C 中的“try catch”会导致内存泄漏?

于 2017-03-15T20:10:38.093 回答