編集 - 以下の問題を 64 ビット対 32 ビットのアーキテクチャの問題に追跡しました...どのように解決したかについては、投稿された回答を参照してください
SudzCを使用して Web サービスの SOAP コードを生成しました。彼らは、デバイスとシミュレーターの両方で、私が正常に使用できたサンプル アプリケーションを提供します。
その後、アプリの構築を開始しました。空のアプリケーション テンプレート (CoreData と ARC が有効になっている) を使用して、SudzC で生成されたファイルを新しい XCode プロジェクトにインポートしました。
最初の SOAP リクエストを起動して実行しました。すべてがシミュレーターで動作します。次に、デバイス (iOS 7.02 を実行する iPhone 5S) で最初のテストを行いました。EXC_BAD_ACCESS
SOAP 要求が実行されるたびに、デバイスはエラーをスローします。
SoapRequest.m
これをファイル、特にconnectionDidFinishLoading
メソッドまで追跡しました。このメソッドはobjc_msgSend
呼び出しを使用して、SOAP 応答データを別のクラス (この場合はビュー コントローラー) のハンドラー メソッドに送り返します。コードは次のとおりです。
SoapRequest.m:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSError* error;
if(self.logging == YES) {
NSString* response = [[NSString alloc] initWithData: self.receivedData encoding: NSUTF8StringEncoding];
NSLog(@"%@", response);
}
CXMLDocument* doc = [[CXMLDocument alloc] initWithData: self.receivedData options: 0 error: &error];
if(doc == nil) {
[self handleError:error];
return;
}
id output = nil;
SoapFault* fault = [SoapFault faultWithXMLDocument: doc];
if([fault hasFault]) {
if(self.action == nil) {
[self handleFault: fault];
} else {
if(self.handler != nil && [self.handler respondsToSelector: self.action]) {
objc_msgSend(self.handler, self.action, fault);
} else {
NSLog(@"SOAP Fault: %@", fault);
}
}
} else {
CXMLNode* element = [[Soap getNode: [doc rootElement] withName: @"Body"] childAtIndex:0];
if(deserializeTo == nil) {
output = [Soap deserialize:element];
} else {
if([deserializeTo respondsToSelector: @selector(initWithNode:)]) {
element = [element childAtIndex:0];
output = [deserializeTo initWithNode: element];
} else {
NSString* value = [[[element childAtIndex:0] childAtIndex:0] stringValue];
output = [Soap convert: value toType: deserializeTo];
}
}
if(self.action == nil) { self.action = @selector(onload:); }
if(self.handler != nil && [self.handler respondsToSelector: self.action]) {
objc_msgSend(self.handler, self.action, output);
} else if(self.defaultHandler != nil && [self.defaultHandler respondsToSelector:@selector(onload:)]) {
[self.defaultHandler onload:output];
}
}
conn = nil;
}
したがって、その行objc_msgSend(self.handler, self.action, output);
は私の問題がある場所のようです。self.handler
私のView Controllerを指しており、self.action
このメソッドを指しています:
TasksViewController.m:
- (void) findItemHandler: (id) value {
// Handle errors
if([value isKindOfClass:[NSError class]]) {
NSLog(@"%@", value);
return;
}
// Handle faults
if([value isKindOfClass:[SoapFault class]]) {
NSLog(@"%@", value);
return;
}
// Do something with the id result
NSLog(@"FindItem returned the value: %@", value);
}
このメソッドへの再エントリは、クラッシュする場所です。(id)value
が SoapRequest クラスから引き継がれていないようです。ARCによって割り当てが解除されていると思います。に置き換えて呼び出しをテストしまし(id)value
たint
:
objc_msgSend(self.handler, self.action, 1);
と
- (void)findItemHandler:(int)value
これは機能します。値変数が時期尚早に破棄されることが問題であると仮定して、それを維持するためにいくつかのことを試みました。SoapRequest.m にプロパティを追加しました。
@property (nonatomic, strong) id value;
次にそれを渡しました:
self.value = output;
objc_msgSend(self.handler, self.action, self.value);
同じ問題。SoapRequest のインスタンスでも同じことを試しました...今、View Controller でプロパティを作成し、そのプロパティを値に設定することで問題を回避できましたが、これを使用してこれを修正する方法に本当に興味があります元のコード。SudzC からダウンロードしたサンプル アプリに戻って、それがどのように機能しているかを確認したところ、そのプロジェクトでは ARC が有効になっていないことがわかりました (!)。
誰か教えてください:
1)割り当てが解除されているという私の仮定が正しい場合output
、ハンドラーメソッドが不正なメモリアドレスを参照する原因になりますか?
2) これがシミュレーターで機能するのはなぜですか? これは、シムに使用可能なメモリが多く、ARC の割り当て解除にそれほど積極的ではないためだと思います...
objc_msgSend
3)通話を維持したい場合、どうすればこれを修正できますか? これがどのように/なぜ起こっているのかを知りたい
4) ここでの の使用法で SudzC が正しい場合objc_msgSend
、まれな状況を除いてこれを直接呼び出すのは悪い習慣だと理解していますか?
ありがとう!