1

最新の10.8.2オペレーティングシステムをインストールし、Xcodeを4.5.2にアップグレードしてから、長い間機能していた自分が作成したアプリケーションで問題が発生し始めました。

アプリケーションには、文字列の配列であるivarNSMutableArrayを構築するバックグラウンドキューでそれ自体を実行するメソッドを持つクラス(CalculateTimeFiles)があります。この配列とステータスカウンターは、NSMutableArrayからメッセージを取り出し、ウィンドウ内のスクロールテキストビューボックスに表示する2番目のクラス(RunResultWindow)によって監視されます。メッセージはCalculateTimeFilesによって生成されるため、RunResultWindowはメッセージを取得してテキストビューにドロップし、CalculateTimeFilesが現在何をしているかをユーザーに知らせます。

このプロセスは長い間正常に機能していましたが、この新しいバージョンのXcodeでは、ARCがディスパッチキューに対して有効になっていると思います(これは新しいことだと思います)。コードはXcodeで正常に実行されますが、アプリケーションをXcodeの外部にエクスポートしてそこで実行すると、爆発します。私が見つけたのは、バックグラウンドのディスパッチキュータスクの最後に何かが発生し、それが原因ですべてがおかしくなっているということです。Xcode自体がCalculateTimeFilesのivarに対してある程度の可観測性を確立し、何かが消えないようにしているため、Xcodeで機能していると思います。

ivar NSMutableArrayの文字列がバックグラウンドタスクではなく、メインキューに強制された別のメソッドで定義されていることを確認しました(私は思います)。

私がこれに乗ることができるどんな助けも素晴らしいでしょう。

関連するいくつかのコードスニペットは次のとおりです。

これはメインアプリデリゲートからのものです:

- (IBAction)runButtonPressed:(id)sender
{
......
......

 CalculateTimeFiles* tempCalculateTimeFiles = [[CalculateTimeFiles alloc] init];

RunResultWindowController = [[RunResultWindow alloc]       
           initWithWindowNibName:@"RunResultWindow"];
RunResultWindowController.localCalculateTimeFiles=tempCalculateTimeFiles;
[RunResultWindowController showWindow:self];

[self.outputfilestring1 becomeFirstResponder];

NSLog(@"before calculate time files");

[tempCalculateTimeFiles calculateOutputFiles:self];

NSLog(@"after calculate time files");


......
......
 }

RunResultWindowで使用されているメソッドは次のとおりです。

- (void)windowDidLoad
{
[super windowDidLoad];

NSWindow *wcWindow;
wcWindow = [self window];
[wcWindow makeKeyAndOrderFront:self];

NSString *teststring;
teststring = @"start output calculations";
[RunResultWindowTextView setString:teststring];
[RunResultWindowTextView display];

localCalculateTimeFiles.localRunResultWindow = self;

[localCalculateTimeFiles addObserver:self
       forKeyPath:@"arraystatuscounter"
          options:NSKeyValueObservingOptionNew
          context:NULL];

}


- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:
   (NSDictionary *)change context:(void *)context
{    

dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(mainQueue, ^{ 

NSInteger arrayCountFromDictionary;
NSString* localDisplayString;
NSString* localNewlinePlusDisplayString;
NSTextStorage *tempTextStorage;

tempTextStorage = [RunResultWindowTextView textStorage];

NSLog(@"in observeValueForKeyPath before display");

arrayCountFromDictionary = [[change objectForKey:NSKeyValueChangeNewKey] integerValue];

if (arrayCountFromDictionary != 0 ){
    arrayCountFromDictionary--;
    localDisplayString = [localCalculateTimeFiles.StatusStrings
        objectAtIndex:arrayCountFromDictionary];
    if (![localDisplayString compare: @"removeobservernow"]){
        NSLog(@"planned removeobserver logic");
        [localCalculateTimeFiles removeObserver:self forKeyPath:@"arraystatuscounter"];}
    if ([localDisplayString compare: @"removeobservernow"]){
        localNewlinePlusDisplayString = [@"\n" 
             stringByAppendingString:localDisplayString];
        [tempTextStorage beginEditing];
        [tempTextStorage replaceCharactersInRange:NSMakeRange([tempTextStorage length] -
              1, 0) withString:localNewlinePlusDisplayString];
        [tempTextStorage endEditing];
        NSLog(@"string before display %@",localDisplayString);
        [RunResultWindowTextView display];}};

NSLog(@"in observeValueForKeyPath after display");


});
}

これがCalculateTimeFilesで機能しているものです。ARCがこれをカバーするようになったため、dispatch_releaseメソッド呼び出しを削除したことに注意してください。

@interface CalculateTimeFiles : NSObject {

NSMutableArray *StatusStrings;
NSInteger arraystatuscounter;
RunResultWindow *localRunResultWindow;

}

@property (nonatomic, retain) NSMutableArray *StatusStrings;
@property  NSInteger arraystatuscounter;
@property RunResultWindow *localRunResultWindow;

- (void) calculateOutputFiles:(id) parameterTimeGenieAppDelegate;
- (void) UpdateStatusTable:(NSString*) statusStringMessage;

@end



- (void) calculateOutputFiles:(TimeGenieAppDelegate*) parameterTimeGenieAppDelegate;
{

dispatch_queue_t backgroundQueue = dispatch_queue_create("Background Queue",NULL);
dispatch_async(backgroundQueue, ^{ 

.... does a bunch of stuff...

   [self UpdateStatusTable:@"stop here a long time"];
    [self UpdateStatusTable:@"new test string very first one"];
    [self UpdateStatusTable:@"===================="];
    [self UpdateStatusTable:@"new test string"];
    [self UpdateStatusTable:@"processing complete"];
    [self UpdateStatusTable:@"removeobservernow"];
    NSLog(@"just before dispatch release");

    // dispatch_release(backgroundQueue);

    [NSThread sleepForTimeInterval: 3.0];
    NSLog(@"just after dispatch release");
    });

NSLog(@"just after thread done");

}



- (void) UpdateStatusTable:(NSString*) statusStringMessage
{
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(mainQueue, ^{

[StatusStrings addObject:[NSString stringWithString:statusStringMessage]];
[self setArraystatuscounter:[StatusStrings count]];

});

}

記述されているUpdateStatusTableのaddObjectは、バックグラウンドプロセスが完了しても消えない新しい文字列を作成すると想定しています(これは悪い考えかもしれません)。

私もクラッシュダンプを持っていますが、それらを読み取る方法が本当にわからないので、そこに役立つものがあるかもしれませんが、私はそれを知りません。私にとって非常に理にかなっている唯一の部分はこれです:

Crashed Thread:  2  Dispatch queue: com.apple.root.default-overcommit-priority

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: EXC_I386_GPFLT

Thread 2 Crashed:: Dispatch queue: com.apple.root.default-overcommit-priority
0   libobjc.A.dylib                 0x00007fff8ea3bf5e objc_release + 14
1   libobjc.A.dylib                 0x00007fff8ea3b230 (anonymous
    namespace)::AutoreleasePoolPage::pop(void*) + 464
2   libdispatch.dylib               0x00007fff93eb2264 _dispatch_worker_thread2 + 410
3   libsystem_c.dylib               0x00007fff8e0b4cab _pthread_wqthread + 404
4   libsystem_c.dylib               0x00007fff8e09f171 start_wqthread + 13

繰り返しますが、私がこれに乗ることができるどんな助けも素晴らしいでしょう。前もって感謝します。

4

2 に答える 2

0

ArcはGCDオブジェクトを解放しません。ブロックの最後で、自分で解放する必要があります。以下の私の編集を参照してください。

- (void) calculateOutputFiles:(TimeGenieAppDelegate*) parameterTimeGenieAppDelegate;
{

dispatch_queue_t backgroundQueue = dispatch_queue_create("Background Queue",NULL);
dispatch_async(backgroundQueue, ^{ 

.... does a bunch of stuff...

   [self UpdateStatusTable:@"stop here a long time"];
    [self UpdateStatusTable:@"new test string very first one"];
    [self UpdateStatusTable:@"===================="];
    [self UpdateStatusTable:@"new test string"];
    [self UpdateStatusTable:@"processing complete"];
    [self UpdateStatusTable:@"removeobservernow"];
    NSLog(@"just before dispatch release");
    [NSThread sleepForTimeInterval: 3.0];
    NSLog(@"just after dispatch release");
    });
dispatch_release(backgroundQueue); // dispatch_release should be here
NSLog(@"just after thread done");

}

すべてがうまくいくことを願っています。

于 2012-11-22T20:34:17.537 に答える
0

Xcode 4.6のテストバージョンをダウンロードすると、問題が解決しました。それは苛立たしい6週間でした。

問題は、実際には、NSMutableArray内のオブジェクトのアドレスを一時的に古くするために使用されたメソッド内の一時オブジェクトでした。オブジェクトはメソッドの「main」ルーチンで宣言され、ループで繰り返し再利用され、オブジェクト配列内のアイテムのアドレスが一時オブジェクトにシャッフルされて使用できるようになりました。ループが終了すると、プログラムはxcodeの外部で爆発しました。これは、(私が思うに)xcode自体が一時オブジェクトの可観測性を確立し、ループ(独自のスコープ範囲を持つ)の割り当てが解除されたときに割り当てが解除されないようにしたためです。SOOOOOO ... Xcodeの外部でのみ発生する奇妙な割り当て解除の問題がある場合は、4.5.2が問題である可能性があると考えてください。

于 2012-12-16T03:54:31.813 に答える