为什么我的 [UIScrollView removeFromSuperview] 导致程序崩溃?

3
以下是崩溃日志。
您知道为什么[UIScrollView removeFromSuperview]可能会导致崩溃吗?滚动视图包含具有不同类型的UIViews的视图层次结构。我还发现,Ad Hoc版本往往会崩溃而不是调试版本。我找不到任何原因。
在iPhone中,相同的视图控制器在不同的流程中加载可以正常工作。但是在iPad上它会崩溃。在iPad中,在容器视图控制器中,只加载viewcontroler.view。
Incident Identifier: EE102239-34D1-4BE7-8B52-41F74AB26203
CrashReporter Key:   2b11ea2a01ac5618e199ffc5a1e1f321600bb6a9
Hardware Model:      iPad3,4
Version:         ??? (???)
Code Type:       ARM (Native)
Parent Process:  launchd [1]

Date/Time:       2013-06-18 15:19:16.132 +0200
OS Version:      iOS 6.1.3 (10B329)
Report Version:  104

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x00000000
Crashed Thread:  0

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   libobjc.A.dylib                 0x3bab7070 prepareForMethodLookup + 20
1   libobjc.A.dylib                 0x3bab6fb2 lookUpMethod + 42
2   libobjc.A.dylib                 0x3bab6f7e _class_lookupMethodAndLoadCache3 + 14
3   libobjc.A.dylib                 0x3bab6638 objc_msgSend_uncached + 24
4   QuartzCore                      0x357f2a72 CA::Layer::contents_visibility_changed(CA::Transaction*, bool) + 50
5   QuartzCore                      0x357f29de CA::Layer::mark_visible(CA::Transaction*, bool) + 190
6   QuartzCore                      0x357f29b2 CA::Layer::mark_visible(CA::Transaction*, bool) + 146
7   QuartzCore                      0x357f29b2 CA::Layer::mark_visible(CA::Transaction*, bool) + 146
8   QuartzCore                      0x357f29b2 CA::Layer::mark_visible(CA::Transaction*, bool) + 146
9   QuartzCore                      0x357f29b2 CA::Layer::mark_visible(CA::Transaction*, bool) + 146
10  QuartzCore                      0x357f28d2 CA::Layer::update_removed_sublayer(CA::Transaction*, unsigned int) + 18
11  QuartzCore                      0x357f255a CA::Layer::remove_sublayer(CA::Transaction*, CALayer*) + 130
12  QuartzCore                      0x357f246a CA::Layer::remove_from_superlayer() + 34
13  UIKit                           0x35a6e92c -[UIView(Hierarchy) removeFromSuperview] + 144
14  UIKit                           0x35b857bc -[UIScrollView removeFromSuperview] + 60
15  MyApp           0x000bde8a -[iPadNavigationController vcAnimationDone] (iPadNavigationController.m:400)
16  UIKit                           0x35a55ab6 -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 154
17  UIKit                           0x35aca8f8 -[UIViewAnimationState animationDidStop:finished:] + 44
18  QuartzCore                      0x35801304 CA::Layer::run_animation_callbacks(void*) + 204
19  libdispatch.dylib               0x3bed55d8 _dispatch_client_callout + 20
20  libdispatch.dylib               0x3bed8e40 _dispatch_main_queue_callback_4CF + 224
21  CoreFoundation                  0x33c051ac __CFRunLoopRun + 1284
22  CoreFoundation                  0x33b78238 CFRunLoopRunSpecific + 352
23  CoreFoundation                  0x33b780c4 CFRunLoopRunInMode + 100
24  GraphicsServices                0x37733336 GSEventRunModal + 70
25  UIKit                           0x35a942b4 UIApplicationMain + 1116

以下是一些代码片段(如所请求),

    previous = showing;
    showing = [ vc retain ];
    showing.view.frame = startFrameIn;
    [ container addSubview:showing.view ];

    CGContextRef context = UIGraphicsGetCurrentContext();
    [ UIView beginAnimations:nil context:context ];
    [ UIView setAnimationDelegate:self ];
    [ UIView setAnimationDidStopSelector:@selector(vcAnimationDone) ];
    [ UIView setAnimationCurve:UIViewAnimationCurveEaseOut ];
    [ UIView setAnimationDuration:0.4 ];

    previous.view.frame = endFrameOut;
    showing.view.frame = detailFrame;

    [ UIView commitAnimations ];
}

- (void) vcAnimationDone {
    if ( previous != nil ) {
        if (previous.view.superview != nil) {
            [previous.view removeFromSuperview];
        }
        [ previous release ];
        previous = nil;
    }

你能发一下导致崩溃的代码吗? - Midhun MP
另一个动画是否仍在运行?似乎有一些消息要发送到“nil”实例。它是在ARC下编译的吗? - Sulthan
尝试在模拟器中运行它,并使用工具查找僵尸。 - Jerome Diaz
你要写哪个版本的iOS?手动引用计数,那些在iOS4中被弃用的动画方法... - Abizern
对于iOS 4.3版本,每次在iPad上按下按钮时,我需要加载4个视图控制器(vc)。并且这些加载都带有动画效果。因此,在加载另一个视图控制器时,可能会出现其他动画正在运行的情况。我无法在调试模式下重现此错误,只有在adhoc模式下才会出现。 - karim
3个回答

2
一个很可能的原因是您正在过度释放scrollview或其中一个视图。调用removeFromSuperview将释放视图而不是简单地减少保留计数。

1
感谢大家提供的答案、技巧和窍门。然而,我想与大家分享的一件事是崩溃的原因。我发现崩溃在不同的线程上发生在不同的时间。我的iPad应用程序中加载了几个视图,其中一些通过按钮按下/菜单从Web服务获取数据。所以我有点困惑是动画、URL连接等导致了崩溃。我尝试启用NSZombie对象,但它没有显示任何信息。然后我尝试使用Guard Malloc。这只在模拟器中运行。神奇的是,我找到了崩溃的代码点。我有一个函数将十六进制字符串转换为数据。在那里,我有一行代码将C字符串置为空终止。我在最后一个索引处分配了0,这导致了崩溃!
tmpCh[count] = 0;

我不知道为什么,但可能在iOS中的内存管理过程中需要一些时间,因此它会在不同线程的不同时间崩溃。但在模拟器中使用Guard malloc时,它总是在这里指出问题,当我重写代码后,崩溃就消失了。

/* Converts a hex string to bytes.
 Precondition:
 . The hex string can be separated by space or not.
 . the string length without space or 0x, must be even. 2 symbols for one byte/char
 . sample input: 23 3A F1 OR 233AF1
 */
+ (NSData *) dataFromHexString:(NSString*)hexString
{

    if (hexString.length < 1) {
        return nil;
    }

    char * tmpCh = (char *) malloc([hexString length] * sizeof(char));
    int count = 0;
    for (int k=0; k<hexString.length;k++) {
        char c = [hexString characterAtIndex:k];

        if (c == (char)0x20) { //skip space
            continue;
        }

        if (c == '0') { // skip 0x
            if(k+1 < hexString.length){
                if ([hexString characterAtIndex:k+1] == 'x'
                    || [hexString characterAtIndex:k+1] == 'X' )
                {
                    k = k + 1;
                    continue;
                }
            }
        }

        tmpCh[count] = c;
        count++;
    }
    tmpCh[count] = 0; // make null terminated string

    if (count % 2) {
        return nil;
    }

    NSString *temp = [[NSString alloc] initWithUTF8String:tmpCh];
    free(tmpCh);

    if ([temp length] % 2 != 0) {
        return  nil;
    }

    NSMutableData *result = [[NSMutableData alloc] init];
    unsigned char byte;
    char hexChars[3] = {0};
    for (int i=0; i < (temp.length/2); i++) {
        hexChars[0] = [temp characterAtIndex:i*2];
        hexChars[1] = [temp characterAtIndex:i*2+1];

        if (![Util isValidChar:hexChars[0]] || ![Util isValidChar:hexChars[1]]) {
            return nil;
        }
        byte = strtol(hexChars, NULL, 16);
        [result appendBytes:&byte length:1];
    }

    NSData * data = [NSData dataWithData:result];
    [result release];
    return data;
}

1
实际上,如果您仍然使用非ARC项目,静态代码分析对于此类错误非常有用。保留/释放平衡问题很难确定,在不完整的方法下几乎不可能,因此建议尽可能发布完整的方法主体。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接