0

私はObjective Cに比較的慣れていないので、URLから情報を読み取って、その情報をNameオブジェクトに追加し、名前オブジェクトを配列に追加しようとしています。URL から情報を正常に読み取ることができ、さらにそれらの情報を配列に追加することに成功しましたが、nameArray に名前を正常に追加できないようです。一番上で配列を宣言し、それを viewDidLoad 関数で初期化します。さらに、メソッド readURLOne、readURLTwo、および readURLThree を呼び出すときに、名前が配列に追加されることを意味します。しかし、配列を確認すると、viewDidLoad でこれらのメソッドを呼び出した後、空になっています。これはなぜでしょうか?

@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
4

2 に答える 2

1

一番上で配列を宣言し、それを viewDidLoad 関数で初期化します。さらに、メソッド readURLOne、readURLTwo、および readURLThree を呼び出すときに、名前が配列に追加されることを意味します。

私が見ることができるように、あなたは readURLOne、readURLTwo、および readURLThree を呼び出していません - それらを NSOperationQueue に追加しています。このような場合、メソッドは非同期的に呼び出され、viewDidLoad の最後に確認した後に nameArray が更新される可能性があります。

メソッドを次のように変更します。

- (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];
} 
于 2015-03-04T21:16:45.557 に答える
0

NSOperationQueues は非同期で動作するため、 にアクセスするまでにそれらが完了するという保証はありませんnameArray

次の行を の前に追加できますNSLog

[queue waitUntilAllOperationsAreFinished];

しかし、実際には、を使用せずに関数を直接呼び出す必要があると思いますNSOperationQueue


呼び出しているメソッドをさらに調べると、ネットワーク操作を実行しているように見えます。これは、既に行ったように別のスレッドで確実に行う必要があるため、完了のためのコールバックを追加するだけで済みます。finish操作を追加することで、これを非常に簡単に行うことができます。

  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
}
于 2015-03-04T21:12:44.853 に答える