2012-03-10 10 views
1

私はBOSSのプログラミングに関するBNRガイドを勉強しています。私がやっていることの要約はこれです。私はtableViewのセクションを管理する柔軟な方法が必要でした。したがって、セクションを保持するNSMutableArrayを構築しました。配列の各オブジェクトはNSDictionaryを介してテーブルセクションを表します。辞書には2つのキーがあり、セクションヘッダーの文字列とセクションの所有物を保持する配列があります。私はストアクラスからallPossesionsを取得し、適切な配列と辞書に並べ替えて保存する少しのルーチンを持っています。私はこれを組み込むために私のコードを書き直す作業をしてきました。そして私は混乱しているロードブロックを打ちました。私のアプリがデバッガで動くとき、何が起こっているかを追跡するためにNSLogをたくさん投げています。私はセクション・アレイの内容にアクセスしてログを記録するのに問題はないようです。あるいは、テーブル・ビューのサポート方法のほとんどがnsdictionariesです。しかし、cellForRowAtIndexpathが呼び出されると、コード神は私に笑いを止めます。どういうわけか私の所有物の配列にアクセスしたりログアウトしたりしようとすると、突然空になります。UITableViewデータソースの問題。私のデータ配列は突然空です。UITableView:cellForRowAtIndexPath:が呼び出されました。

私の人生にとってはこれを理解できません。私はこれで1日ちょっと頭を打っていて、どんなインプットや助けも喜んで受け入れるだろう。以下はitemsViewController.hと実装です。ログの混乱を見落とし、セクションをコメントアウトしてください。私はこれを理解しようとしてきたので、人々はこれに私のアプローチについて変更する必要があるかもしれないことを私に教えてくれるかもしれません。また、テーブルが最初は空であり、何かを追加しようとするまでアプリが何の問題もないことに注意する価値があります。ここで

// 
// ItemsViewController.h 
// HomePwnr 

#import <Foundation/Foundation.h> 
#import "ItemDetailViewController.h" 

@interface ItemsViewController : UITableViewController 
{ 
    NSMutableArray *sections; // variable to hold the number of sections 
} 
-(void)addNewPossession:(id)sender; 
-(void)divideSections; 
@end 

は、最後にここに実装

// 
// ItemsViewController.m 
// HomePwnr 

#import "ItemsViewController.h" 
#import "PossessionStore.h" 
#import "Possession.h" 

@implementation ItemsViewController 

- (id) init 
{ 
     NSLog(@"ItemsViewController init called"); 
     // Call the superclass's designated initializer 
    self = [super initWithStyle:UITableViewStyleGrouped]; 

    if (self) { 
     // create a new barItem that will send addNePossession: to itemsViewController 
     UIBarButtonItem *bbi = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addNewPossession:)]; 

     // Set this barButtonItem as the right item in the Navigation item 
     [[self navigationItem] setRightBarButtonItem:bbi]; 

     //The Navigation item retains its buttons so release bbi 
     [bbi release]; 

     // set the title of the navigation item 
     [[self navigationItem] setTitle:@"Homepwner"]; 

     //[[self navigationItem] setLeftBarButtonItem:[self editButtonItem]]; 
    } 
    sections = [[[NSMutableArray alloc] init] retain]; // added the extra retain here to make sure my sections weren't getting released pre maturely 

     // set up sections here by dividing allPossessions 
    [self divideSections]; 
    return self; 
} 

- (id) initWithStyle:(UITableViewStyle)style 
{ 
    return [self init]; 
} 

-(void)divideSections 
{ 
    NSLog(@"divideSections called"); 
     // For simplicity we'll just empty out the sections array and rebuild it each time we add or modify a possesion 
    [sections removeAllObjects]; 

    NSArray *cheapStuff = [[NSArray alloc] initWithArray:[[PossessionStore defaultStore] possesionsFromPredicate:@"valueInDollars < 50"]]; 
    NSArray *expensiveStuff = [[NSArray alloc] initWithArray:[[PossessionStore defaultStore] possesionsFromPredicate:@"valueInDollars >= 50"]]; 


    // we'll be making an NSDictionary for each section. it will hold an array of possesions for each section and it's key will serve as the sections header 
    if ([cheapStuff count] > 0) { 
     NSMutableDictionary *section1 = [NSMutableDictionary dictionaryWithObject:cheapStuff forKey:@"Possessions"]; 
     [section1 setValue:@"Cheap Stuff" forKey:@"Header"]; 
     [sections addObject:section1]; 
     // sections now retains NSDictionary so we release it 
     [section1 release]; 
    } 
    if ([expensiveStuff count] > 0) { 
     NSMutableDictionary *section2 = [NSMutableDictionary dictionaryWithObject:expensiveStuff forKey:@"Possessions"]; 
     [section2 setValue:@"Cheap Stuff" forKey:@"Header"]; 
     [sections addObject:section2]; 
     // sections now retains NSDictionary so we release it 
     [section2 release]; 
    } 
     //now our arrays are retained by the dictionarys so we release them 
    [cheapStuff release]; 
    [expensiveStuff release]; 
    NSLog(@" End of divideSections sections holding %@", sections); 

} 

/* 
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    ItemDetailViewController *detailViewController = [[[ItemDetailViewController alloc] init] autorelease]; 
     // NSArray *possessions = [[PossessionStore defaultStore] allPossessions]; 
     // give the detail view controller a pointer to the possesion object in row 
     // get the NSDictionary located at the section index, get the dictionary's array, get the possession at row index 
    Possession *p = [[[sections objectAtIndex:[indexPath section]] objectAtIndex:0] objectAtIndex:[indexPath row]]; 
    [detailViewController setPossession:p]; 


     // push it onto the navigationControllers stack 
    [[self navigationController] pushViewController:detailViewController animated:YES]; 


} 


- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
     ////If the table view is asking to commit the delete command 
    if (editingStyle == UITableViewCellEditingStyleDelete) { 

//PossessionStore *ps = [PossessionStore defaultStore]; 
// NSArray *possessions = [ps allPossessions]; 
// Possession *p = [possessions objectAtIndex:[indexPath row]]; 

     int section = [indexPath section]; 
     int row = [indexPath row]; 
     Possession *p = [[[sections objectAtIndex:section] objectAtIndex:0] objectAtIndex:row]; 
     [[[PossessionStore defaultStore] allPossessions] removePossession:p]; 

     // remove the row from the table view with an animation 
     [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES]; 
    } 
} 

-(void) tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath{ 
    [[PossessionStore defaultStore] movePossessionAtIndex:[sourceIndexPath row] toIndex:[destinationIndexPath row]]; 
} 
*/ 


-(void)addNewPossession:(id)sender 
{ 
    // 
    NSLog(@"addNewPossession called - sections = %@", sections); 
    [[PossessionStore defaultStore] createPossession]; 
    //NSLog(@"Possesion store now holds %@", [[PossessionStore defaultStore] allPossessions]); 

     //we've added a new possession so we'll divide out the sections again 
    [self divideSections]; 
    //NSLog(@"addNewPossession exiting - sections = %@", sections); 

     //tableview returns the tablesview 
    [[self tableView] reloadData]; 
    //NSLog(@"table view reloading data - sections = %@", sections); 

} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 
    int numSections = [[(NSArray *)[sections objectAtIndex:section] objectForKey:@"Possessions"] count]; 
    //NSLog(@"numberOfRowsInSection: called for section %i, returning %i.", section, numSections); 
    return numSections; 
} 

- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView 
{ 
    NSLog(@"returning number of sections: %i", [sections count]); 
     // return the count of the sections array 
    return [sections count]; 
} 

- (NSString *) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section 
{ 
    NSLog(@"tableView:titleForHeaderInSectionCalled - sections = %@", sections); 
     //Configure the header titles based on the number of sections 
    if ([sections count] <= 1) { 
     // return simple title for only one section in table 
     NSLog(@"Returning My Stuff"); 
     return @"My Stuff"; 
    } else { 
     NSLog(@"The header returned is %@", [[sections objectAtIndex:section] objectForKey:@"Header"]); 
     // or return the key for the dictionary entry for the current section 
     return [[[sections objectAtIndex:section] objectAtIndex:section] objectForKey:@"Header"]; 
    } 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    NSLog(@"tableView:cellForRowAtIndexPath called for section %d, Row %d", [indexPath section], [indexPath row]); 
    NSLog(@"Sections = %@", sections); 
    NSLog(@"The Dictionary is %@", [sections objectAtIndex:[indexPath section]]); 
    //NSLog(@"thisSection array should be %@", (NSArray *)[[sections objectAtIndex:thisSection] objectForKey:@"Possessions"]); 
    //NSArray *thisSectionArray = [[sections objectAtIndex:thisSection] objectForKey:@"Possessions"]; 
     // Check for reusable cell 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"]; 
     // If there is no cell of this type create a new one 
    if (!cell) { 
     cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"UITableViewCell"] autorelease]; 
    } 

     // get the NSDictionary located at the section index, get the dictionary's array, get the possession at row index 
     //Possession *p = [thisSection objectAtIndex:[indexPath row]]; 
     //[[cell textLabel] setText:[p description]]; 
    [[cell textLabel] setText:@"cell text"]; 

    return cell; 
} 

-(void)viewWillAppear:(BOOL)animated 
{ 
    [self divideSections]; 
    [super viewWillAppear:YES]; 
    NSLog(@"viewWillAppear called - sections = %@", sections); 
} 

-(void)viewDidUnload 
{ 
    [super viewDidUnload]; 
    NSLog(@"viewDidUnload called - sections = %@", sections); 
} 

@end 

は、アプリケーションを実行しようとしているから、私のログです。小さな緑色のインジケータは、アプリケーションのクラッシュ後にcellForRow .......の間にセクションの内容をログに記録しようとする行のすぐ上にあります。

2012-03-10 06:22:00.177 HomePwnr[44399:f803] ItemsViewController init called 
2012-03-10 06:22:00.180 HomePwnr[44399:f803] divideSections called 
2012-03-10 06:22:00.181 HomePwnr[44399:f803] End of divideSections sections holding (
) 
2012-03-10 06:22:00.188 HomePwnr[44399:f803] divideSections called 
2012-03-10 06:22:00.189 HomePwnr[44399:f803] End of divideSections sections holding (
) 
2012-03-10 06:22:00.189 HomePwnr[44399:f803] returning number of sections: 0 
2012-03-10 06:22:00.190 HomePwnr[44399:f803] returning number of sections: 0 
2012-03-10 06:22:00.191 HomePwnr[44399:f803] viewWillAppear called - sections = (
) 
2012-03-10 06:22:04.234 HomePwnr[44399:f803] addNewPossession called - sections = (
) 
2012-03-10 06:22:04.235 HomePwnr[44399:f803] divideSections called 
2012-03-10 06:22:04.237 HomePwnr[44399:f803] End of divideSections sections holding (
     { 
     Header = "Cheap Stuff"; 
     Possessions =   (
      "Shiny Gun (7R3K0): Worth $40, recorded on 2012-03-10 11:22:04 +0000" 
     ); 
    } 
) 
2012-03-10 06:22:04.238 HomePwnr[44399:f803] returning number of sections: 1 
2012-03-10 06:22:04.239 HomePwnr[44399:f803] tableView:titleForHeaderInSectionCalled - sections = (
     { 
     Header = "Cheap Stuff"; 
     Possessions =   (
      "Shiny Gun (7R3K0): Worth $40, recorded on 2012-03-10 11:22:04 +0000" 
     ); 
    } 
) 
2012-03-10 06:22:04.240 HomePwnr[44399:f803] Returning My Stuff 
2012-03-10 06:22:04.241 HomePwnr[44399:f803] tableView:titleForHeaderInSectionCalled - sections = (
     { 
     Header = "Cheap Stuff"; 
     Possessions =   (
      "Shiny Gun (7R3K0): Worth $40, recorded on 2012-03-10 11:22:04 +0000" 
     ); 
    } 
) 
2012-03-10 06:22:04.241 HomePwnr[44399:f803] Returning My Stuff 
2012-03-10 06:22:04.243 HomePwnr[44399:f803] tableView:cellForRowAtIndexPath called for section 0, Row 0 
(lldb) 
+0

誰でもアドバイスをありますか? – vichudson1

答えて

2

よく、2つの提案。最初はARC(Automatic Reference Counts)に移動して、コンパイラがすべての保持/解放などを処理するようにします。

これは短く、すぐに問題が発生するのは、section1とsection2を解放するdivideSectionsです。どちらも自動リリースされた辞書を返す簡易ルーチンdictionaryWithObjectで作成されます。したがって、allocルーチンによって保持され、配列セクションに追加されても、保持カウントはゼロであるため、いつでも消えることがあります。 (これは、 "alloc、copy、またはretain"を持つルーチンだけが保持されたオブジェクトを返すという慣例のために当てはまることが分かります)

これらを見つける最も簡単な方法は、XcodeにBuildではなくAnalyzeを要求することです。これは、このような多くの他の問題と同様に、多くのメモリ問題を指摘するでしょう。

このコードは、以下のコメントに関連しています。セクションはNSArrayプロパティでなければなりません。そして、あなたはこのようにゲッターを書く:

-(void) sections { 
    if (!sections) { 
     <<code from dividesections that ends with...>> 
     self.sections = [NSArray arrayWithObjects: section1,section2,nil]; 
    } 
    return sections; 
} 

あなたはセクションを知っているその方法は常に正しいこと、そしてあなたがdivideSectionsを呼び出すときに心配する必要はありません。

+0

あなたの答えをありがとう。私はメモリ管理の問題があると思った。 ARCについては、私が取り組んでいる本では、ARCより前に出版されたので、それをカバーしていません。 ARCの変更点を突き止めようとするのではなく、本に沿って読むことが最善であると考えました。私は記憶管理(私はまだ持っていない、CH3の別の読書のように見える)の確かな理解を考え、ARCを学ぶ前に傷つけませんでした。アナライザを実行してこれらの問題をどのように指摘したのかを確認した後、私が帰った後で変更を実装します。そのチップもありがとう。私は後でそれがどのように判明するのかを掲載する予定です。 – vichudson1

+0

うまくいきます。私はまた、セクションをプロパティにします – mackworth

+0

プロパティでは、それを@property宣言で設定し、それを合成することを意味しますか?なぜこれはただの配列に必要なのでしょうか?それは十分なヘッダーのインスタンス変数を宣言していないか?これはitemsViewControllerクラス自体によってのみアクセスされます。 – vichudson1

関連する問題