Objective-C syntax - how to initialize an array that "lives" deep in an object hierarchy
I think this sketch will add clarity to what I am trying to achieve.
Essentially, I want to create iPhone app that allows user to select a schoolDistrict from a tableview and the app will slide that view over and reveal the next tableview full of schools. When they select a school, the next view displays the teachers, finally, when they select a teacher, it will display the courses taught by that teacher.
So, I am trying to construct some sample data for my viewtable "drilldown" and I am struggling to populate such a hierarchical data structure.
I'm hoping the sketch below helps.
https://skitch.com/aibkwik/rqu41/photo-feb-13-10-30-15-pm.jpg
original post follows:
UPDATED: I am trying to alloc an array that is deeply embedded in an object hierarchy. The top object instance is call "thisYear" and it has an array in it called "courses". "courses" also contains, among other things, an array called scoreCatetories. How would you initialize and add an object to the "scoreCategories" array? I've tried numerous things, including:
I'm trying all manner of combinations such as the one below - nothing is working.
...
[[thisYear courses] scoreCategories] = [[NSMutableArray alloc] init];
[[[thisYear courses] scoreCategories] addObject:myNewObj];
...
I'm trying to load some sample data - the code below is located in the
didFinishLaunchingWithOptions
function of the appDelegate.
Here is the code snippet that is causing me grief. Please see the .h files, further down in this post.
dGradeURin *thisYear;
thisYear = [[dGradeURin alloc] init];
[thisYear.howManyTerms initWithInteger: 4];
thisYear.gradeURin = @"Freshman";
//this paragraph compiles and runs fine
dCourse *tmpcourse;
tmpcourse = [[dCourse alloc] init];
tmpcourse.cName =@"Computer Science";
tmpcourse.school =@"Freedom High";
thisYear.courses = [[NSMutableArray alloc] init];
[thisYear.courses addObject:tmpcourse];
dScoringCategory *tmpSC;
tmpSC = [[dScoringCategory alloc] init];
tmpSC.name = @"Quizzes";
//these two lines are not working
[[thisYear courses] setScoreCategories:[[[NSMutableArray alloc] init] autorelease]];
[[[thisYear courses] scoreCategories] addObject:tmpSC];
//both the above lines compile with a warning: NSMutableArray may not respond to -setScoreCategories
// when I run the program, the first line causes crash with an exception... See stack trace at far bottom
Here are the .h header file snippets for each interface object definitions, in essence...
@interface dGradeURin : NSObject {
NSNumber *howManyTerms;
NSString *gradeURin;
NSMutableArray *courses;
}
@property (retain, nonatomic) NSNumber *howManyTerms;
@property (retain, nonatomic) NSString *gradeURin;
@property (retain, nonatomic) NSMutableArray *courses;
@interface dCourse : NSObject {
NSString *cName;
NSString *teacher;
NSString *school;
NSString *school_term;
NSString *gradingMethod;
NSNumber *whichterm;
NSMutableArray *scoreCategories;
}
@property (retain, nonatomic) NSString *cName;
@property (retain, nonatomic) NSString *school;
@property (retain, nonatomic) NSMutableArray *scoreCategories;
@interface dScoringCategory : NSObject {
NSString *name;
NSMutableArray *scores;
}
@property (retain, nonatomic) NSString *name;
@property (retain, nonatomic) NSMutableArray *scores;
@interface dScore : NSObject {
NSNumber *score;
NSDate *scoreDate;
NSString *description;
}
@property (retain, nonatomic) NSDate *scoreDate;
@property (retain, nonatomic) NSNumber *score;
@property (retain, nonatomic) NSString *description;
Here is the stack trace
2011-02-13 21:49:43.559 GradeJanx[86526:40b] -[__NSArrayM setScoreCategories:]: unrecognized selector sent to instance 0x4b76660
2011-02-13 21:49:43.561 GradeJanx[86526:40b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayM setScoreCategories:]: unrecognized selector sent to instance 0x4b76660'
*** Call stack at first throw:
(
0 CoreFoundation 0x00db0be9 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x00f055c2 objc_exception_throw + 47
2 CoreFoundation 0x00db26fb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x00d22366 ___forwarding___ + 966
4 CoreFoundation 0x00d21f22 _CF_forwarding_prep_0 + 50
5 GradeJanx 0x00002c50 -[AppDelegate_iPhone application:didFinishLaunchingWithOptions:] + 881
6 UIKit 0x002ba1fa -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1163
7 UIKit 0x002bc55e -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 439
8 UIKit 0x002c6db2 -[UIApplication handleEvent:withNewEvent:] + 1533
9 UIKit 0x002bf202 -[UIApplication sendEvent:] + 71
10 UIKit 0x002c4732 _UIApplicationHandleEvent + 7576
11 GraphicsServices 0x016e6a36 PurpleEventCallback + 1550
12 CoreFoundation 0x00d92064 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 52
13 CoreFoundation 0x00cf26f7 __CFRunLoopDoSource1 + 215
开发者_JS百科 14 CoreFoundation 0x00cef983 __CFRunLoopRun + 979
15 CoreFoundation 0x00cef240 CFRunLoopRunSpecific + 208
16 CoreFoundation 0x00cef161 CFRunLoopRunInMode + 97
17 UIKit 0x002bbfa8 -[UIApplication _run] + 636
18 UIKit 0x002c842e UIApplicationMain + 1160
19 GradeJanx 0x000028bc main + 102
20 GradeJanx 0x0000284d start + 53
Okay, this is all sorts of messed up, so let's just step back a little bit. An array is an indexed set of objects. An index is a non-negative integer that represents the location of an object. Each object is accessible in the array by an index. You can't do [[thisYear courses] scoreCategories]
and expect anything to work, because you haven't actually provided an index to the object in the array. You could do something like [[thisYear courses] objectAtIndex:0]
, which would return the first element in the array. You could also do [[thisYear courses] objectAtIndex:1]
, which would return the second element in the array.
Whenever you insert an element into an NSMutableArray
, it inserts it as the last object in the array. For instance, if the NSMutableArray
you're inserting your object into doesn't have any elements contained within it, the index of the element you're inserting is 0. If it have 1 element in it, then the index of the element you're inserting would have an index of 1.
The code you're probably looking for is this:
NSMutableArray *scoreCategories = [NSMutableArray array];
[scoreCategories addObject:myNewObj];
[[thisYear courses] addObject:scoreCategories];
However, there are a lot of other problems with doing things this way. Before proceeding any further, I'd recommend you spend some time with a good Objective-C book.
Update
Okay, let's take another look at this. This is pretty tough without the context in which this code appears, but we'll try anyway.
dGradeURin *thisYear = [[[dGradeURin alloc] init] autorelease];
thisYear.howManyTerms = [NSNumber numberWithInteger:4];
thisYear.gradeURin = @"Freshman";
NSMutableArray *courses = [NSMutableArray array];
//set up a temporary course
dCourse *temporaryCourse = [[[dCourse alloc] init] autorelease];
temporaryCourse.cName = @"Computer Science";
temporaryCourse.school = @"Freedom High";
temporaryCourse.scoreCategories = [NSMutableArray array];
dScoringCategory *temporaryScoringCategory = [[[dScoringCategory alloc] init] autorelease];
temporaryScoringCategory.name = @"Quizzes";
[temporaryCourse.scoreCategories addObject:temporaryScoringCategory];
[courses addObject: temporaryCourse];
thisYear.courses = courses;
This first line creates an autoreleased object. That means that at some point, the memory this object is taken up will be freed for use somewhere else. If you don't free the memory of an object, then it will keep taking up memory, whether you ever use it or not. For more about this (and you really need to understand it to use Objective-C), check out Apple's documentation.
A couple of other things. If this is homework, and it looks like it might be from the content, then be sure you tag it as homework. I don't mind helping you here because it looks like most of your problems are syntactic, but don't forget next time.
Second, I don't know where you got those classes, but assuming you're using the interfaces correctly, they appear to be poorly designed. There's a lot of understanding required to make things work well rather than just work. I'd still recommend reading that book I linked above if you really want to learn this stuff.
If it's a declared property (with the @property
syntax), then you can use the dot notation to set the property value:
// This assumes that scoreCategories has either the 'retain' or 'copy' property;
// if it instead uses 'assign', then you'll need to retain this array.
[thisYear courses].scoreCategories = [NSMutableArray arrayWithObjects:myNewObj, nil];
If it's not a declared property, just access it using the standard arrow notation:
[thisYear courses]->scoreCategories = [[NSMutableArray alloc] initWithObjects:myNewObj, nil];
Not the cleanest approach, but anyway:
[[thisYear courses] setScoreCategories:[[[NSMutableArray alloc] init] autorelease]];
[[[thisYear courses] scoreCategories] addObject:myNewObj];
Something like
for (Course *course in thisYear.courses) {
course.scoreCategories = [[[NSMutableArray alloc] init] autorelease];
}
I hate being that guy, but this kind of deep inspection (borrowed term there, hah!) smells like bad design to me.
Here's what i would do:
Have a property courses
of the thisYear
object that get's populated when needed. courses
is an array that contains Course
objects. The Course
object has a property called scoreCategories
and also a Method addScoreCategory
. So for your code above, you'd do a
Course * currentCourse = [[thisYear courses] objectAtIndex:0]; // assuming you want the first course
if ([currentCourse isKindOfClass:[Course class]]) {
[currentCourse addScoreCategory:myNewObj];
}
In either the addScoreCategory
or the init method of the Course
class you'd create an NSMutableArray and assign it to the scoreCategories
property.
精彩评论