我在网络请求中提供了一个json数组,并将其存储在NSMutableArray
中。第一次运行正常。但是,当我刷新我的屏幕,并且执行一个新的web请求,将json存储在同一个数组中时,问题就开始了
如何清除我的数组以存储来自网络请求的新json?
在我存储json的数组下面:
#import <Foundation/Foundation.h>
@class Singleton;
@protocol SingletonDelegate <NSObject>
@end
@interface SingletonClass : NSObject
// ...
@property (nonatomic, strong) NSMutableArray *uData;
@end
#import "SingletonClass.h"
@implementation SingletonClass
static SingletonClass *sharedInstance = nil;
// Get the shared instance and create it if necessary.
+ (SingletonClass *)sharedInstance {
if (sharedInstance == nil) {
sharedInstance = [[super allocWithZone:NULL] init];
}
return sharedInstance;
}
- (id)init
{
self = [super init];
if (self) {
// ...
self.uData = [[NSMutableArray alloc] init]; // store json array from web-request
}
return self;
}
@end
这里有3个变种,我尝试在数组中重新存储json。第一个Web请求按预期工作,但如果我执行另一个Web请求,我会收到错误...
#import "AFHTTPRequestOperationManager.h"
#import "SingletonClass.h"
@interface WebApi : AFHTTPRequestOperationManager <SingletonDelegate>
@property (nonatomic, strong) SingletonClass *sshare;
-(void)getUserStream;
@end
#import "WebApi.h"
#define kApiHost @"http://foo.net"
#define kApiPath @"bar"
@implementation WebApi
-(id)init {
self = [super init];
if (self != nil) {
self.sshare = [SingletonClass sharedInstance];
}
return self;
}
-(void)getUserStream {
NSString *URLString = [NSString stringWithFormat:@"%@/%@/pics/user", kApiHost, kApiPath];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[self setAuthHeader:manager];
// clear uData
[self.sshare.uData removeAllObjects]; // Breakpoint set
[manager GET:URLString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
// Variant 1
self.sshare.uData = responseObject;
// Variant 2
NSMutableArray *tmp = [NSMutableArray arrayWithArray:responseObject];
self.sshare.uData = [tmp copy];
// Variant 3
NSMutableArray *tmp = [NSMutableArray arrayWithArray:responseObject];
self.sshare.uData = [tmp mutableCopy];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
DLog(@"Error: %@, responseString: %@", error, operation.responseString);
}];
}
@end
[1417:60b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFArray removeObjectAtIndex:]: mutating method sent to immutable object'
*** First throw call stack:
(0x2f851f03 0x39fe6ce7 0x2f851e45 0x2f7cee7b 0x2f79b769 0x3d377 0x3aeb5 0x320b66c7 0x320b6663 0x320b6633 0x320a1d7b 0x321e1eef 0x3a4cfd53 0x3a4d4817 0x3a4cfd3f 0x3a4d13ef 0x3a4d2673 0x2f81c679 0x2f81af45 0x2f7857a9 0x2f78558b 0x346f26d3 0x320e4891 0x63569 0x3a4e4ab7)
libc++abi.dylib: terminating with uncaught exception of type NSException
[1425:60b] -[__NSArrayI removeAllObjects]: unrecognized selector sent to instance 0x156f5910
[1425:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI removeAllObjects]: unrecognized selector sent to instance 0x156f5910'
*** First throw call stack:
(0x2f851f03 0x39fe6ce7 0x2f855837 0x2f85412f 0x2f7a30d8 0x2c2ff 0x29e3d 0x320b66c7 0x320b6663 0x320b6633 0x320a1d7b 0x321e1eef 0x3a4cfd53 0x3a4d4817 0x3a4cfd3f 0x3a4d13ef 0x3a4d2673 0x2f81c679 0x2f81af45 0x2f7857a9 0x2f78558b 0x346f26d3 0x320e4891 0x52569 0x3a4e4ab7)
libc++abi.dylib: terminating with uncaught exception of type NSException
[1392:60b] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 3 beyond bounds for empty array'
*** First throw call stack:
(0x2f851f03 0x39fe6ce7 0x2f7880cd 0xefbef 0x321b4199 0x3215b3fb 0x3215ac51 0x32081305 0x31cfd31b 0x31cf8b3f 0x31cf89d1 0x31cf83e5 0x31cf81f7 0x31d4bd45 0x34b1b75d 0x3053c5c9 0x2f811c4d 0x2f81c83f 0x2f81c7db 0x2f81afa7 0x2f7857a9 0x2f78558b 0x346f26d3 0x320e4891 0x119569 0x3a4e4ab7)
libc++abi.dylib: terminating with uncaught exception of type NSException
答案 0 :(得分:1)
responseObject
是NSArray
(在您的情况下,它也可能是
NSDictionary
,具体取决于JSON响应。)
self.sshare.uData = responseObject;
将此(不可变的)NSArray
分配给self.sshare.uData
,并且无关紧要
属性声明为NSMutableArray
。因此,稍后调用removeAllObjects
在这个对象崩溃。
也是如此
self.sshare.uData = [tmp copy];
因为copy
也会返回NSArray
,即使在NSMutableArray
上进行了调用。
最后,
self.sshare.uData = [tmp mutableCopy];
实际上在属性中存储了一个可变数组。在这种情况下,因为你崩溃了 不要打电话
[self.tableView reloadData]
通知表格视图数据源已更改。
实际上,在开始获取之前,您不必清空数组。 只需分配新值并在调用完成块时重新加载表视图:
[manager GET:URLString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.sshare.uData = responseObject;
// or, if you need a mutable array:
// self.sshare.uData = [responseObject mutableCopy];
[self.tableView reloadData];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
DLog(@"Error: %@, responseString: %@", error, operation.responseString);
}];
答案 1 :(得分:1)
你的第一个变体是因为某个地方你得到的是NSArray,而不是NSMutableArray(可能是你第一次得到JSON)。您可能希望使用mutableCopy而不是arrayWithArray。
但这一切都没有实际意义:你不需要大惊小怪。将第一个JSON转换为数组时,将其保留为数组(除非您需要更改其内容)。然后,当你得到第二个json数组时,只需指定数组指针指向它,而不是原始数组。像这样:
@property(nonatomic, strong) NSArray * myCurrentJson;
self.myCurrentJson = [mydownloadedJSonString JSONvalue];
然后在你的代码中稍后获得一个新的JSON数组时,只需设置:
self.myCurrentJson = [myNewDownloadedJsonString JSONvalue];
这样myCurrentJson总是指向一个有效的json块,你不必为mutable大惊小怪,因为那些数组不会改变。当你替换数组时,旧的数组不再有任何引用,因此ARC会将它释放到内存中。如果您需要改变值,只需在原始数组上执行mutableCopy,然后在该数组中进行更改。