iPhone SDK Tableview Datasource singleton error
- by mrburns05
I basically followed apple "TheElements" sample and changed "PeriodicElements" .h & .m to my own "SortedItems" .h & .m
During compile I get this error:
"Undefined symbols:
"_OBJC_CLASS_$_SortedItems",
referenced from:
__objc_classrefs__DATA@0 in SortedByNameTableDataSource.o ld:
symbol(s) not found collect2: ld
returned 1 exit status "
here is my SortedItems.m file
#import "SortedItems.h"
#import "item.h"
#import "MyAppDelegate.h"
@interface SortedItems(mymethods)
// these are private methods that outside classes need not use
- (void)presortItemsByPhysicalState;
- (void)presortItemInitialLetterIndexes;
- (void)presortItemNamesForInitialLetter:(NSString *)aKey;
- (void)presortItemsWithPhysicalState:(NSString *)state;
- (NSArray *)presortItemsByNumber;
- (NSArray *)presortItemsBySymbol;
- (void)setupItemsArray;
@end
@implementation SortedItems
@synthesize statesDictionary;
@synthesize itemsDictionary;
@synthesize nameIndexesDictionary;
@synthesize itemNameIndexArray;
@synthesize itemsSortedByNumber;
@synthesize itemsSortedBySymbol;
@synthesize itemPhysicalStatesArray;
static SortedItems *sharedSortedItemsInstance = nil;
+ (SortedItems*)sharedSortedItems {
@synchronized(self) {
if (sharedSortedItemsInstance == nil) {
[[self alloc] init]; // assignment not done here
}
}
return sharedSortedItemsInstance;
// note: Xcode (3.2) static analyzer will report this singleton as a false positive
// '(Potential leak of an object allocated')
}
+ (id)allocWithZone:(NSZone *)zone {
@synchronized(self) {
if (sharedSortedItemsInstance == nil) {
sharedSortedItemsInstance = [super allocWithZone:zone];
return sharedSortedItemsInstance; // assignment and return on first allocation
}
}
return nil; //on subsequent allocation attempts return nil
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX; //denotes an object that cannot be released
}
- (void)release {
//do nothing
}
- (id)autorelease {
return self;
}
// setup the data collection
- init {
if (self = [super init]) {
[self setupItemsArray];
}
return self;
}
- (void)setupItemsArray {
NSDictionary *eachItem;
// create dictionaries that contain the arrays of Item data indexed by
// name
self.itemsDictionary = [NSMutableDictionary dictionary];
// physical state
self.statesDictionary = [NSMutableDictionary dictionary];
// unique first characters (for the Name index table)
self.nameIndexesDictionary = [NSMutableDictionary dictionary];
// create empty array entries in the states Dictionary or each physical state
[statesDictionary setObject:[NSMutableArray array] forKey:@"Solid"];
[statesDictionary setObject:[NSMutableArray array] forKey:@"Liquid"];
[statesDictionary setObject:[NSMutableArray array] forKey:@"Gas"];
[statesDictionary setObject:[NSMutableArray array] forKey:@"Artificial"];
MyAppDelegate *ad = (MyAppDelegate *)[[UIApplication sharedApplication]delegate];
NSMutableArray *rawItemsArray = [[NSMutableArray alloc] init];
[rawItemsArray addObjectsFromArray:ad.items];
// iterate over the values in the raw Items dictionary
for (eachItem in rawItemsArray)
{
// create an atomic Item instance for each
Item *anItem = [[Item alloc] initWithDictionary:eachItem];
// store that item in the Items dictionary with the name as the key
[itemsDictionary setObject:anItem forKey:anItem.title];
// add that Item to the appropriate array in the physical state dictionary
[[statesDictionary objectForKey:anItem.acct] addObject:anItem];
// get the Item's initial letter
NSString *firstLetter = [anItem.title substringToIndex:1];
NSMutableArray *existingArray;
// if an array already exists in the name index dictionary
// simply add the Item to it, otherwise create an array
// and add it to the name index dictionary with the letter as the key
if (existingArray = [nameIndexesDictionary valueForKey:firstLetter])
{
[existingArray addObject:anItem];
} else {
NSMutableArray *tempArray = [NSMutableArray array];
[nameIndexesDictionary setObject:tempArray forKey:firstLetter];
[tempArray addObject:anItem];
}
// release the Item, it is held by the various collections
[anItem release];
}
// release the raw Item data
[rawItemsArray release];
// create the dictionary containing the possible Item states
// and presort the states data
self.itemPhysicalStatesArray = [NSArray arrayWithObjects:@"something",@"somethingElse",@"whatever",@"stuff",nil];
[self presortItemsByPhysicalState];
// presort the dictionaries now
// this could be done the first time they are requested instead
[self presortItemInitialLetterIndexes];
self.itemsSortedByNumber = [self presortItemsByNumber];
self.itemsSortedBySymbol = [self presortItemsBySymbol];
}
// return the array of Items for the requested physical state
- (NSArray *)itemsWithPhysicalState:(NSString*)aState {
return [statesDictionary objectForKey:aState];
}
// presort each of the arrays for the physical states
- (void)presortItemsByPhysicalState {
for (NSString *stateKey in itemPhysicalStatesArray) {
[self presortItemsWithPhysicalState:stateKey];
}
}
- (void)presortItemsWithPhysicalState:(NSString *)state {
NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"title"
ascending:YES
selector:@selector(localizedCaseInsensitiveCompare:)] ;
NSArray *descriptors = [NSArray arrayWithObject:nameDescriptor];
[[statesDictionary objectForKey:state] sortUsingDescriptors:descriptors];
[nameDescriptor release];
}
// return an array of Items for an initial letter (ie A, B, C, ...)
- (NSArray *)itemsWithInitialLetter:(NSString*)aKey {
return [nameIndexesDictionary objectForKey:aKey];
}
// presort the name index arrays so the items are in the correct order
- (void)presortItemsInitialLetterIndexes {
self.itemNameIndexArray = [[nameIndexesDictionary allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
for (NSString *eachNameIndex in itemNameIndexArray) {
[self presortItemNamesForInitialLetter:eachNameIndex];
}
}
- (void)presortItemNamesForInitialLetter:(NSString *)aKey {
NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"title"
ascending:YES
selector:@selector(localizedCaseInsensitiveCompare:)] ;
NSArray *descriptors = [NSArray arrayWithObject:nameDescriptor];
[[nameIndexesDictionary objectForKey:aKey] sortUsingDescriptors:descriptors];
[nameDescriptor release];
}
// presort the ItemsSortedByNumber array
- (NSArray *)presortItemsByNumber {
NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"acct"
ascending:YES
selector:@selector(compare:)] ;
NSArray *descriptors = [NSArray arrayWithObject:nameDescriptor];
NSArray *sortedItems = [[itemsDictionary allValues] sortedArrayUsingDescriptors:descriptors];
[nameDescriptor release];
return sortedItems;
}
// presort the itemsSortedBySymbol array
- (NSArray *)presortItemsBySymbol {
NSSortDescriptor *symbolDescriptor = [[NSSortDescriptor alloc] initWithKey:@"title"
ascending:YES
selector:@selector(localizedCaseInsensitiveCompare:)] ;
NSArray *descriptors = [NSArray arrayWithObject:symbolDescriptor];
NSArray *sortedItems = [[itemsDictionary allValues] sortedArrayUsingDescriptors:descriptors];
[symbolDescriptor release];
return sortedItems;
}
@end
I followed the sample exactly - don't know where I went wrong.
Here is my "SortedByNameTableDataSource.m"
#import "SortedByNameTableDataSource.h"
#import "SortedItems.h"
#import "Item.h"
#import "ItemCell.h"
#import "GradientView.h"
#import "UIColor-Expanded.h"
#import "MyAppDelegate.h"
@implementation SortedByNameTableDataSource
- (NSString *)title {
return @"Title";
}
- (UITableViewStyle)tableViewStyle {
return UITableViewStylePlain;
};
// return the atomic element at the index
- (Item *)itemForIndexPath:(NSIndexPath *)indexPath {
return [[[SortedItems sharedSortedItems] itemsWithInitialLetter:[[[SortedItems sharedSortedItems] itemNameIndexArray] objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];
}
// UITableViewDataSource methods
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = @"ItemCell";
ItemCell *itemCell = (ItemCell *)[tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (itemCell == nil) {
itemCell = [[[ItemCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];
itemCell = CGRectMake(0.0, 0.0, 320.0, ROW_HEIGHT);
itemCell.backgroundView = [[[GradientView alloc] init] autorelease];
}
itemCell.todo = [self itemForIndexPath:indexPath];
return itemCell;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// this table has multiple sections. One for each unique character that an element begins with
// [A,B,C,D,E,F,G,H,I,K,L,M,N,O,P,R,S,T,U,V,X,Y,Z]
// return the count of that array
return [[[SortedItems sharedSortedItems] itemNameIndexArray] count];
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
// returns the array of section titles. There is one entry for each unique character that an element begins with
// [A,B,C,D,E,F,G,H,I,K,L,M,N,O,P,R,S,T,U,V,X,Y,Z]
return [[SortedItems sharedSortedItems] itemNameIndexArray];
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
return index;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// the section represents the initial letter of the element
// return that letter
NSString *initialLetter = [[[SortedItems sharedSortedItems] itemNameIndexArray] objectAtIndex:section];
// get the array of elements that begin with that letter
NSArray *itemsWithInitialLetter = [[SortedItems sharedSortedItems] itemsWithInitialLetter:initialLetter];
// return the count
return [itemsWithInitialLetter count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
// this table has multiple sections. One for each unique character that an element begins with
// [A,B,C,D,E,F,G,H,I,K,L,M,N,O,P,R,S,T,U,V,X,Y,Z]
// return the letter that represents the requested section
// this is actually a delegate method, but we forward the request to the datasource in the view controller
return [[[SortedItems sharedSortedItems] itemNameIndexArray] objectAtIndex:section];
}
@end