2014年11月8日土曜日

SKProductsRequestでハマった。抜け出したけど。

前回に引き続き、iOSアプリの開発ネタです。初めてっていうのは、いろいろな問題にぶち当たりますな。

原因不明でアプリがクラッシュすることが何度かあり、どうやら、アプリ内課金の関係で、Appleのサーバに問い合わせに行っている最中に、「遅い!もういいよ!」みたいな感じで画面遷移(具体的には、ナビゲーションの「戻る」を押す)をしてしまうと、ごく稀にこの問題が発生する、ということまで絞り込むことができた。
ごく稀にというのが、まあ、厄介なところ。

ちなみに、アプリがクラッシュした時のXcode(ちなみにバージョンは6.1)の表示はこんな感じ。

コードがこれ↓


スタックがこれ↓


これだけだと、さっぱり、意味がわからない。

"Enqueued from com.apple.root.default-qos"と"EXC_BAD_ACCESS"とかでググっても、なかなかこれというのが見つからないし、なんと言っても、"Enqueued from com.apple.root.default-qos"と"SKProductsRequest"の組み合わせで検索結果がゼロというのに参った。
SKProductsRequestのstartメソッド呼ばない限りクラッシュしないので、この関係だってことは間違い無いと思うんだけど…。

そして、結局、自分で、何が原因なのかわかりました。ので、情報共有です。

こんなコードを書いていたんですよ。どこかで見たコードのコピペですけど。
- (void)startRequest
{
    SKProductsRequest* productRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithArray:productIdentifiers]];
    productRequest.delegate = self;
    [productRequest start];
}
これだと、サーバからのレスポンスを受け取った時に、selfがdeallocateされてしまった後だと、まずいことになるんですよね。productRequestの後始末が考慮されていない。

というわけで、僕が採った解決法はこれ。
まず、ヘッダファイルでこんな宣言。
@property (nonatomic, strong) SKProductsRequest *productRequest;
そして、本体コードでは、
- (void)startRequest
{
    _productRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithArray:productIdentifiers]];
    _productRequest.delegate = self;
    [_productRequest start];
}


これに加えて、viewWillDisappearで、delegateを無効化してやる処理を加えました。
- (void)viewWillDisappear:(BOOL)animated { _productRequest.delegate = nil; [[SKPaymentQueue defaultQueue] removeTransactionObserver:self]; }


そしたら、(今のところ?)ばっちり、っぽいです。なんか自信なさげな書き方で恐縮ですが。いかんせん、稀にしか起こらない問題なので断言が難しいのです。

0 件のコメント:

コメントを投稿