Я создал простой HttpClient с AFNetworking.iOS селектор отключает приложение
HttpClient *client = [[HttpClient alloc] initWithTarget:(id)target
before:(SEL)before
success:(SEL)success
failure:(SEL)failure
timeout:(SEL)timeout]
Таким образом, контроллер может регистрировать функцию обратного вызова, когда он выполняет запрос HTTP. И вот как я написал функции обратного вызова:
- (void)successMethod:(id)response {
// LogDebug(@"Success: %@", response);
self.lock = false;
if (self.target == nil || self.successCallback == nil) {
return;
}
if ([self.target respondsToSelector:self.successCallback]) {
[self.target performSelector:self.successCallback withObject:response];
}
}
Но здесь я нашел проблему. Когда запрос возвращается быстро, он работает нормально. Но если запрос возвращается после очень долгого времени, а между тем пользователь меняет вид. Затем он сбрасывает приложение и генерирует исключение, например, селектор не может быть выполнен на ноль-объекте.
Так что я хочу знать, сделал ли я это правильно и есть ли способ решить эту проблему? Каковы наилучшие методы реализации этого?
=====
Update:
К сожалению, я не ставил журнал ошибок. Но на самом деле нет большой информации, которую я могу получить. Иногда даже нет журнала. Я поставил здесь скриншот и надеюсь, что это может помочь.
Я только получаю это и нет журнала исключений.
==== Update
И надеюсь, что это может помочь
#import "HttpClient.h"
#import "AFNetworking.h"
#import "Logging.h"
@interface HttpClient()
@property int retryCounter;
@property(nonatomic) NSString *action;
@property(nonatomic) NSString *url;
@property(nonatomic) NSDictionary *param;
@property(nonatomic) AFHTTPRequestOperationManager *manager;
@end
@implementation HttpClient
- (id)initWithTarget:(id)target
before:(SEL)before
success:(SEL)success
failure:(SEL)failure
timeout:(SEL)timeout {
self = [super init];
if (self) {
self.target = target;
self.before = before;
self.success = success;
self.failure = failure;
self.timeout = timeout;
self.lock = false;
self.retryMaxCounter = 2;
self.retryCounter = 0;
self.manager = [AFHTTPRequestOperationManager manager];
self.manager.requestSerializer = [AFJSONRequestSerializer serializer];
self.manager.responseSerializer = [AFJSONResponseSerializer serializer];
}
return self;
}
- (void)request:(NSString *)action
url:(NSString *)url
param:(NSDictionary *)param {
self.action = action;
self.url = url;
self.param = param;
[self beforeMethod];
[self request];
}
- (void)request {
if (self.lock) {
return;
}
if ([[self.action lowercaseString] isEqual:@"get"]) {
// Get
LogDebug(@"Send GET request.");
self.lock = true;
LogInfo(@"%@\n%@", self.url, self.param);
[self.manager GET:self.url
parameters:self.param
success:^(AFHTTPRequestOperation *operation, id responseObject) {
[self successMethod:responseObject];
}
failure:^(AFHTTPRequestOperation operation, NSError error) {
if ([operation.response statusCode] == 500) {
[self failureMethod:operation.responseObject];
} else {
[self timeoutMethod];
}
}];
} else if ([[self.action lowercaseString] isEqual:@"post"]) {
// POST
LogDebug(@"Send POST request.");
self.lock = true;
LogInfo(@"%@\n%@", self.url, self.param);
[self.manager POST:self.url
parameters:self.param
success:^(AFHTTPRequestOperation *operation, id responseObject) {
[self successMethod:responseObject];
}
failure:^(AFHTTPRequestOperation operation, NSError error) {
if ([operation.response statusCode] == 500) {
[self failureMethod:operation.responseObject];
} else {
[self timeoutMethod];
}
}];
} else {
LogError(@"Not supported request method.");
}
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
- (void)beforeMethod {
LogDebug(@"Before requesting.");
if (self.target == nil || self.before == nil) {
return;
}
if ([self.target respondsToSelector:self.before]) {
[self.target performSelector:self.before];
}
}
- (void)successMethod:(id)success {
// LogDebug(@"Success: %@", success);
self.lock = false;
if (self.target == nil || self.success == nil) {
return;
}
if ([self.target respondsToSelector:self.success]) {
[self.target performSelector:self.success withObject:success];
}
}
- (void)failureMethod:(id)failure {
LogDebug(@"Failure: %@", failure);
self.lock = false;
if (self.target == nil || self.failure == nil) {
return;
}
if ([self.target respondsToSelector:self.failure]) {
[self.target performSelector:self.failure withObject:failure];
}
}
- (void)timeoutMethod {
LogError(@"Request timeout.");
self.lock = false;
self.retryCounter++;
if (self.retryCounter < self.retryMaxCounter) {
[self request];
} else {
if (self.target == nil || self.timeout == nil) {
return;
}
if ([self.target respondsToSelector:self.timeout]) {
[self.target performSelector:self.timeout];
}
}
}
#pragma clang diagnostic pop
@end
Спасибо всем большое!
==== Update
Я нашел проблему. Это было связано с тем, что я установил targe в assign
вместо weak
. Для разницы между assign
и weak
, пожалуйста, обратитесь к stackoverflow question
Я предполагаю, что вы выполняете асинхронный запрос? – gikygik
@gikygik Да, конечно. Некоторое представление требует, чтобы ответ возвращался первым. Таким образом, все функции просмотра чертежа помещаются в обратный вызов успеха. И другие предназначены для обработки ошибок. Но если я изменил представление до того, как запрос вернется, он потерпит крах. – Ciel
Я предполагаю, что свойство successCallback присваивается, я прав? –