1

ブロックと ARC を使用していますが、状況によっては、iOS がリリース ビルドでのみクラッシュすることがわかりました。このようなコードの書き方は間違っていました。

-(IBAction)clickedButtonA:(UIBarButtonItem*)sender event:(UIEvent*)event {
  NSMutableArray *arrRows = [NSMutableArray arrayWithCapacity:0];
  #warning this code only crash on Release Build.... Don't use this
  NSMutableDictionary * dicRow = [NSMutableDictionary dictionaryWithCapacity:0];
  [arrRows addObject:dicRow];
  dispatch_block_t block = ^{
    NSString *str = [NSString stringWithFormat:@"%@",[_tweet valueForKey:@"text"]];
    [[UIPasteboard generalPasteboard] setString:str];
  };
  [dicRow setValue:block forKey:kDicKeyLinkPopBlock];

  NSMutableArray *sections = [NSMutableArray arrayWithObject:arrRows];
  TOVLinkPopoverViewController *controller= [[TOVLinkPopoverViewController alloc] init];
  controller.arrayLink = sections;
}

また、他のコントローラーからブロックにアクセスすると、リリース ビルドでのみクラッシュします。ブロックをコピーする必要があることを学びました

[dicRow setValue:[block copy] forKey:kDicKeyLinkPopBlock];

NSMutableDictionary のような非ブロック対応クラスの場合。

問題は、「なぜリリース ビルドでしかクラッシュしないのですか?」ということです。これが「クラッシュするはず」であることはわかっていますが、これはブロックの使用方法が間違っていましたが、この種のバグを早期に発見できるように、デバッグ ビルドでクラッシュすることを願っています。

もう 1 つの質問は、「このコードをデバッグ ビルドでクラッシュさせるビルド設定はありますか?」です。

サンプル コードは gitHub ( https://github.com/tomohisa/iOS_PopoverMenu_Notification ) から実行できます。

ViewController.m を参照して、コメント アウトされたコードを見つけます (リリース時にのみクラッシュします)。

4

1 に答える 1

6

を追加する必要があるのは正しいです[block copy]。これは、そのブロックが現在のスタック フレーム (つまり 内clickedButtonA:event:) で作成されているためですが、それをディクショナリに追加し、おそらく後でそれを引き出すためです。後でそれを引き出して使用すると、元のスタック フレームがなくなり、実際にはブロックではない (ほとんどの場合そうではない) ランダム メモリへのポインターが得られます。

ブロックをコピーすると、現在スタック上にある場合はヒープにコピーされ、既にヒープ上にある場合は保持されます。これは、コンテキスト間で受け渡しできる有効なブロックがあることを意味します。

リリース モードでのみクラッシュが見られる理由は、リリース モードがスタックの処理方法を完全に変更するコンパイラの最適化を有効にするためです。おそらく、デバッグ モードで問題を確認できなかったのは非常に幸運であり、単にアプリの設計方法が変わっただけだったのでしょう。

于 2012-05-20T20:56:16.560 に答える