2013-07-31 3 views
1

게임 서버 회사의 앱을 개발 중이며 앱의 일부에 사용자가 자신의 게임 서버 목록과 온라인, 오프라인, 방법 등을 볼 것을 요구합니다. 많은 플레이어, 서버 이름 등이 있습니다.이 데이터는 모두 MySQL 데이터베이스에서 업데이트 된 웹에서 호스팅되는 PHP 파일에서 찾을 수 있습니다.이 데이터베이스는 볼 때 JSON을 출력합니다.SIGABRT는 indexPath.row를 사용하여 NSArray에 액세스합니다.

아래 코드를 사용하면 작동하지 않는 것 같습니다. 보기를로드하고 바로 NSDictionary *myServer = [servers objectAtIndex:indexPath.row];이있는 행에 "스레드 1 : 신호 SIGABRT"오류가 표시됩니다. indexPath.row을 제거하고 0 또는 1로 바꾸면 내 스토리 보드의 UITableView에 데이터가 표시됩니다. 단, JSON 파일 (0 또는 1)의 해당 항목에 대해서만 연속으로 4 회 표시됩니다. 나는 클라이언트가 100 개의 서버를 가질 수도 있고 고정 된 번호로 유지할 수도 없다. 단지 서버가 5 개 밖에 없어서 indexPath.row과 같은 것이 필요하다. 아래에서는 JSON이 서버에서 제공 될 때 앱의 코드에서 직접 액세스하고 앱의 코드에서 직접 액세스하는 경우도 첨부했습니다.

누군가가 내게 문제가 무엇인지 알려주고 고유 한 솔루션을 제안 할 수 있다면 정말 고맙겠습니다. 내 상황이 SIGABRT 오류를 제거하고 일단 우리가 그것을 지금처럼 TableView 4 번 표시되지 않는지 확인하십시오.

내 헤더 파일 :

#import <UIKit/UIKit.h> 
#import "ServerDetailViewController.h" 

@interface SecondViewController : UITableViewController { 
    IBOutlet UITableView *mainTableView; 

    NSDictionary *news; 
    NSMutableData *data; 
} 

@property (weak, nonatomic) IBOutlet UIBarButtonItem *refreshServersButton; 

- (IBAction)refreshServers:(id)sender; 

@end 

내 주요 파일을 서버에서

#import "SecondViewController.h" 

@interface SecondViewController() 

@end 

@implementation SecondViewController 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; 

    NSURL *url = [NSURL URLWithString:@"REDACTED"]; 
    NSURLRequest *request = [NSURLRequest requestWithURL:url]; 
    [[NSURLConnection alloc] initWithRequest:request delegate:self]; 
} 

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 
{ 
    data = [[NSMutableData alloc] init]; 
} 

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)theData 
{ 
    [data appendData:theData]; 
} 

- (void)connectionDidFinishLoading:(NSURLConnection *)connection 
{ 
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 

    news = [NSJSONSerialization JSONObjectWithData:data options:nil error:nil]; 
    [mainTableView reloadData]; 
} 

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 
{ 
    UIAlertView *errorView = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Unable to load server list. Make sure you are connect to either 3G or Wi-Fi or try again later." delegate:nil cancelButtonTitle:@"Dismiss" otherButtonTitles:nil, nil]; 
    [errorView show]; 
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 
} 

- (void)didReceiveMemoryWarning 
{ 
    [super didReceiveMemoryWarning]; 
} 

- (int)numberOfSectionsInTableView:(UITableView *)tableView 
{ 
    return 1; 
} 

- (int)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 
    return [news count]; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 

    UIColor *colorGreen = [UIColor colorWithRed:91.0f/255.0f green:170.0f/255.0f blue:101.0f/255.0f alpha:1.0f]; 
    UIColor *colorRed = [UIColor redColor]; 

    static NSString *CellIdentifier = @"MainCell"; 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 

    if (cell == nil) { 
     cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; 
    } 

    UILabel *serverName = (UILabel *)[cell viewWithTag:100]; 
    UILabel *serverPlayers = (UILabel *)[cell viewWithTag:101]; 
    UILabel *serverStatus = (UILabel *)[cell viewWithTag:102]; 
    UILabel *serverOfflineName = (UILabel *)[cell viewWithTag:103]; 

    serverPlayers.textColor = [UIColor grayColor]; 

    NSDictionary *resultDict = [news objectForKey:@"result"]; 
    NSArray *servers = [resultDict objectForKey:@"servers"]; 
    NSDictionary *myServer = [servers objectAtIndex:indexPath.row]; 

    NSString *titleOfServer = [myServer objectForKey:@"title"]; 
    NSNumber *statusOfServer = [NSNumber numberWithInt:[[myServer objectForKey:@"status"] intValue]]; 
    NSNumber *playersOnServer = [NSNumber numberWithInt:[[myServer objectForKey:@"players"] intValue]]; 

    if ([[statusOfServer stringValue] isEqualToString:@"0"]) { 

     serverName.text = @""; 
     serverOfflineName.text = titleOfServer; 
     serverStatus.textColor = colorRed; 
     serverStatus.text = @"OFFLINE"; 
     serverPlayers.text = @""; 
     cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 

    } else if ([[statusOfServer stringValue] isEqualToString:@"1"]) { 

     serverName.text = titleOfServer; 
     serverOfflineName.text = @""; 
     serverStatus.textColor = colorGreen; 
     serverStatus.text = @"ONLINE"; 
     serverPlayers.text = [playersOnServer stringValue]; 
     cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 

    } else if ([[statusOfServer stringValue] isEqualToString:@"2"]) { 

     serverName.text = @""; 
     serverOfflineName.text = titleOfServer; 
     serverStatus.textColor = [UIColor blueColor]; 
     serverStatus.text = @"BUSY"; 
     serverPlayers.text = @""; 
     cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 


    } else if ([[statusOfServer stringValue] isEqualToString:@"3"]) { 

     serverName.text = @""; 
     serverOfflineName.text = titleOfServer; 
     serverStatus.textColor = [UIColor grayColor]; 
     serverStatus.text = @"SUSPENDED"; 
     serverPlayers.text = @""; 
     cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 


    } else if ([[statusOfServer stringValue] isEqualToString:@"-1"]) { 

     serverName.text = @""; 
     serverOfflineName.text = titleOfServer; 
     serverStatus.textColor = [UIColor orangeColor]; 
     serverStatus.text = @"CRITICAL ERROR"; 
     serverPlayers.text = @""; 
     cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 


    } 

    return cell; 
} 

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    ServerDetailViewController *detail = [self.storyboard instantiateViewControllerWithIdentifier:@"detail"]; 
    [self.navigationController pushViewController:detail animated:YES]; 
} 

- (IBAction)refreshServers:(id)sender { 
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; 

    NSURL *url = [NSURL URLWithString:@"REDACTED"]; 
    NSURLRequest *request = [NSURLRequest requestWithURL:url]; 
    [[NSURLConnection alloc] initWithRequest:request delegate:self]; 
} 

@end 

JSON 코드 :. {"status":"OK","error":"","debug":"2 server(s)","result":{"servers":[{"id":1,"title":"Test","players":0,"slots":10,"status":3},{"id":2,"title":"Creative Spawn","players":0,"slots":5,"status":-1}]}} 코드에서

+0

objectAtIndex를 고정 숫자 (이 경우 1)로 설정하면 각 서버가 4 번 표시되는 방식을 보여주는 스크린 샷입니다. http://i.stack.imgur.com/K0cay.png – user2638403

+0

먼저 나머지 오류 메시지를 읽고 포함하십시오. 둘째, 장래에 사이트 외부에 호스팅되지 않고 여기에 질문의 본문에 코드를 포함하십시오. 셋째, 코드를 줄여서 [문제를 재현하는 데 필요한 최소한의 시간을 절약하십시오] (http://sscce.org/). 당신은 종종 그 과정에서 자신의 문제를 해결할 수 있습니다. –

+1

그래서 실패하면 indexPath.row의 값은 무엇입니까? (NSLog indexPath.row.) –

답변

2

이 오류의 원인과 같습니다 (단 , 나는 그 모든 것을 읽지 않았다.)

- (int)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 
    return [news count]; //counted number of items in your whole json object. 
} 

하고 cellForRowAtIndexPath에서 : (NSIndexPath *) indexPath

NSDictionary *resultDict = [news objectForKey:@"result"]; 
NSArray *servers = [resultDict objectForKey:@"servers"]; 
// you used a different array(an item of the whole json array). 
// Since news object has more items than servers, it caused an out of bound here. 
NSDictionary *myServer = [servers objectAtIndex:indexPath.row]; 

하고 코드

- (int)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 
    NSDictionary *resultDict = [news objectForKey:@"result"]; 
    NSArray *servers = [resultDict objectForKey:@"servers"]; 
    return [servers count]; //counted number of items in your whole json object. 
} 
+0

정말 고마워요! 나는 지금 어디에서 잘못되었는지 잘 알고, 좋은 일을 계속 지킵니다! -Michael – user2638403

+0

@ user352891의 권장 사항을 확인하십시오. 유지 보수의 악몽에서 벗어날 수 있습니다. –

2

TL에 다음을보십시오; DR
충돌에 대한 이유를, 당신은 뉴스를 사용하고 .count는 테이블의 행 수와 같지만 서버 배열에서 indexPath.row를 참조합니다 (이는 보장되지 않음).

여기에 몇 가지있다 : 첫째

,이 네트워크의 매우 능숙 방법이 아니다, 당신은 iOS5를을 지원하기 때문에, 나는 다음과 같은 방법 (또는 비슷한)를 사용하여 제안 :

[NSURLConnection sendAsynchronousRequest:theRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { 
    NSString *dataString = [[NSString alloc] initWithBytes:[data bytes] length:[[data bytes] length] encoding:NSUTF8StringEncoding]; 
}]; 

둘째로, 나는 컨트롤러를 위해 데이터를 관리하는 것이 아니라, 누군가가 언급했듯이, 현재 코드는 가능한 한 쉽게 읽을 수있는 것이 아니라 (유지 보수하는 것만 큼!) MVC model을 강력히 추천합니다.셋째

, 난 당신이 더 방어적인 코딩을 사용하는 것이 좋습니다 아래를 통해 읽는 동안 내가 발견 한 점은 다음과 같습니다

  1. 소식은 오히려 잘 [NSJSONSerialization JSONObjectWithData:data options:nil error:nil]; ,, 모든 사전을 반환 보장 할 수 없습니다 ;
  2. 크래시의 원인은 news.count를 테이블의 행 수로 사용하면서도 서버 배열에서 indexPath.row를 참조하는 것입니다 (이는 보장되지 않습니다). 있다).

내가 너라면, 네트워킹을 단순화하고 간단한 모델 (예 : Server)을 만든 다음이 모델과 관련된 JSON을 구문 분석하도록하십시오. 지금까지 서버 객체에 NSArray를 반환하는 'retrieveServers'와 같은 정적 메소드를 서버 모델에 포함 시키려고했습니다.

그 방법, 컨트롤러가하고있는 모든입니다

[self setNews:[Server retrieveServers]]; 
[_tableView reloadData]; 

오히려 컨트롤러에 관련이없는 코드를 많이하는 것보다 -이 유지 보수와 가독성을 증가 할 것이다. 당신이 이렇게 경사 된 경우

, 당신은 예를 들어, 오히려 모델을 통해 직접 멤버를 참조하는 것보다, 사용자의 접근을 다른 조치를 취할하고 제공 할 수있다 :

Server *currentServer = nil; 
if(self.news.count > indexPath.row) { 
    currentServer = [_news objectAtIndex:indexPath.row]; 
} 

[serverPlayers setText:(currentServer ? [currentServer getPlayers] : [Server defaultPlayerValue]] 
위의 코드는 것을 확인하여 안전한되고있는

배열은 우리가 필요로하는 것과 적어도 같은 수의 요소를 가지고 있으며 둘째, 테이블 셀에 값을 할당 할 때 (재사용 될 수 있으므로 가능한 모든 실행 분기에 대해 정상적인 값으로 설정해야합니다.). 위의 작업의 장점은 가독성, 중앙 집중식 기본값, 유지 관리 용이성입니다.

위의 팁을 사용할 다른 이유가 없다면 디버깅을 돕는 몇 가지 포인터를 제공하려고 애쓰는 것이 과장된 것 같습니다 (TL; DR 추가; /).