Reputation: 35
I am relatively new to Objective C and I am trying to read information from a URL then add its info to my Name object then add the name objects to an array. I am able to read the info from the URLs fine and furthermore I am successful in adding their info to an array however I cannot seem to successfully add the names to my nameArray. I declare the array at the top and initialize it in the viewDidLoad function then furthermore the names are meant to be added to the array when I call the methods readURLOne, readURLTwo and readURLThree. However, when I check the array, after calling these methods in viewDidLoad, it is empty. Why might this be?
@interface ViewController () {
Name *n1;
Name *n2;
Name *n3;
NSMutableArray *nameArray; //this is the array I am having trouble with
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
nameArray = [[NSMutableArray alloc] init];
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(readURLOne)object:nil];
[queue addOperation:operation];
operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(readURLTwo)object:nil];
[queue addOperation:operation];
operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(readURLThree) object:nil];
[queue addOperation:operation];
NSLog(@"NAME ARRAY: %lu", (unsigned long)[nameArray count]); //This is where I am trying to check if they are added to the array, the are not
}
-(void) readURLOne {
NSURL *dataURL = [NSURL URLWithString:@"http://example.org/data/1.txt"];
NSArray *tmp = [NSArray arrayWithContentsOfURL:dataURL];
for (NSString *str in tmp){ //add contents of URL successfully to tmp
NSLog(@"%@", str);
}
n1 = [[Name alloc] init];
[n1 setFirstName:tmp[0]];
[n1 setLastName:tmp[1]];
[n1 setNumber:tmp[2]];
[nameArray addObject:n1];
}
-(void) readURLTwo {
NSURL *dataURL = [NSURL URLWithString:@"http://example.org/data/2.txt"];
NSArray *tmp = [NSArray arrayWithContentsOfURL:dataURL];
for (NSString *str in tmp){
NSLog(@"%@", str);
}
n2 = [[Name alloc] init];
[n2 setFirstName:tmp[0]];
[n2 setLastName:tmp[1]];
[n2 setNumber:tmp[2]];
[nameArray addObject:n2];
}
-(void) readURLThree {
NSURL *dataURL = [NSURL URLWithString:@"http://example.org/data/3.txt"];
NSArray *tmp = [NSArray arrayWithContentsOfURL:dataURL];
for (NSString *str in tmp){
NSLog(@"%@", str);
}
n3 = [[Name alloc] init];
[n3 setFirstName:tmp[0]];
[n3 setLastName:tmp[1]];
[n3 setNumber:tmp[2]];
[nameArray addObject:n3];
}
-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return nameArray.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = @"Cell";
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.firstName.text = [[nameArray objectAtIndex:indexPath.row] getFirstName];
cell.lastName.text = [[nameArray objectAtIndex:indexPath.row] getLastName];
return cell;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
Upvotes: 0
Views: 43
Reputation: 14030
NSOperationQueue
s operate asynchronously, so there's no guarantee that they will be complete by the time you're accessing nameArray
.
You could add this line before your NSLog
:
[queue waitUntilAllOperationsAreFinished];
But really, I think you should probably just call the functions directly without using an NSOperationQueue
.
On further inspection of the methods you're calling, it looks like you're performing network operations. This should definitely be done on a different thread like you've already done, so you really just need to add a callback for the completion. You could do this pretty simply by adding a finish
operation:
NSInvocationOperation *completionOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(urlDataRead) object:nil];
// ...
[completionOperation addDependency:operation];
// ...
[completionOperation addDependency:operation];
// ...
[completionOperation addDependency:operation];
[queue addOperation:completionOperation];
}
- (void)urlDataRead {
NSLog(@"NAME ARRAY: %lu", (unsigned long)[nameArray count]); //This is where I am trying to check if they are added to the array, the are not
}
Upvotes: 0
Reputation: 17043
I declare the array at the top and initialize it in the viewDidLoad function then furthermore the names are meant to be added to the array when I call the methods readURLOne, readURLTwo and readURLThree.
As I can see you are NOT calling readURLOne, readURLTwo and readURLThree - you are adding them to NSOperationQueue. In such a case your methods are called asynchronously and nameArray is probably updated after you check it at the end of viewDidLoad.
Change your method to:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
nameArray = [[NSMutableArray alloc] init];
NSOperationQueue *queue = [NSOperationQueue new];
queue.maxConcurrentOperationCount = 1; // It is needed to avoid synchronisation problems with nameArray
NSInvocationOperation *operation1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(readURLOne)object:nil];
[queue addOperation:operation1];
NSInvocationOperation *operation2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(readURLTwo)object:nil];
[queue addOperation:operation2];
NSInvocationOperation *operation3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(readURLThree) object:nil];
[queue addOperation:operation3];
NSOperation *finalOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"NAME ARRAY: %lu", (unsigned long)[nameArray count]);
}];
[finalOperation addDependency:operation1];
[finalOperation addDependency:operation2];
[finalOperation addDependency:operation3];
[queue addOperation:finalOperation];
}
Upvotes: 1