我使用AFNetworking创建了一个简单的HttpClient。
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];
}
}
但在这里我发现了一个问题。当请求快速返回时,它工作正常。但是如果请求在很长一段时间后回来,同时用户会更改视图。然后它崩溃应用程序并抛出一个异常,例如,无法在nil对象上执行选择器。
所以我想知道我是否以正确的方式做到了,有没有办法解决这个问题?实现这一目标的最佳做法是什么?
=====
更新
抱歉,我没有输入错误日志。但实际上我没有太多的信息。有时甚至没有日志。我在这里放了一个截图,希望它可以提供帮助。
我只能得到这个,并且没有异常日志。
==== 更新
希望这可以提供帮助
#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
非常感谢你们!
==== 更新
我发现了问题。这是因为我将目标设置为assign
而不是weak
。有关assign
和weak
之间的差异,请参阅stackoverflow question
答案 0 :(得分:0)
您需要为目标使用弱自引用。 我不确定你的实现是什么样的,但这可能会给你一个提示:
__weak typeof(self) weakSelf = self;
HttpClient *client = [[HttpClient alloc] initWithTarget:weakSelf
before:(SEL)before
success:(SEL)success
failure:(SEL)failure
timeout:(SEL)timeout]
另一种更好的IMO方式是使用块来进行AFNetworking完成。