Версия SudzC ARC - вызов objc_msgSend вызывает EXC_BAD_ACCESS с использованием 64-битной архитектуры
Редактировать - яМы отслеживали приведенную ниже проблему с проблемой 64-битной и 32-битной архитектуры ... см. мой опубликованный ответ, чтобы узнать, как я решил эту проблему ».
мы использовалиSudzC генерировать SOAP-код для веб-службы. Они предоставляют вам пример приложения, которое я смог успешно использовать как на устройстве, так и на симуляторе.
Затем я начал создавать свое приложение. Я импортировал сгенерированные файлы SudzC в новый проект XCode, используя пустой шаблон приложения (с включенными CoreData и ARC).
Я получил первый SOAP-запрос и все работает - все работает в симуляторе - и затем я отправился на первый тест на устройстве (iPhone 5S под управлением iOS 7.02). Устройство выбрасываетEXC_BAD_ACCESS
ошибка каждый раз, когда запускается SOAP-запрос.
мы отследили это доSoapRequest.m
файл, а именноconnectionDidFinishLoading
метод. Этот метод используетobjc_msgSend
вызов для отправки данных ответа SOAP обратно в метод-обработчик в другом классе (в данном случае, мой контроллер представления). Вот's код:
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 ... Теперь я смог обойти эту проблему, создав свойство в контроллере представления и установив для этого свойства значение, но мне действительно любопытно, как это исправить, используя оригинальный код. Я вернулся к примеру приложения, которое я скачал с SudzC, чтобы посмотреть, как это работает, и оказалось, что ARC не включен для этого проекта (!).
Может кто-нибудь сказать мне:
1) Если я прав в своем предположении, чтоoutput
освобождается, в результате чего метод обработчика ссылается на неверный адрес памяти?
2) Почему это работает на симуляторе? Я предполагаю, что это потому, что у сима гораздо больше памяти, поэтомуТ, как агрессивно с освобождением ARC ...
3) Как я мог это исправить, предполагая, что я хочу сохранитьobjc_msgSend
вызов? Я хочу узнать, как / почему это происходит
4) Если SudzC правильно в их использовании здесьobjc_msgSend
Насколько я понимаю, это плохая практика называть это напрямую, кроме как в редких случаях?
Спасибо!