Why does my app crash - objective-c

I made a class. This is the h file.
// MyClass.h
#import <Foundation/Foundation.h>
#interface MyClass : NSObject <NSCoding> {
NSString *string1;
NSString *string2;
}
#property (nonatomic, retain) NSString *string1;
#property (nonatomic, retain) NSString *string2;
#end
This is the m file
// MyClass.m
#import "MyClass.h"
#implementation MyClass
#synthesize string1, string2;
- (void)encodeWithCoder:(NSCoder *)coder;
{
NSLog(#"encodeWithCoder");
[coder encodeObject:string1 forKey:#"string1"];
[coder encodeObject:string2 forKey:#"string2"];
}
- (id)initWithCoder:(NSCoder *)coder;
{
NSLog(#"initWithCoder");
self = [super init];
self.string1 = [coder decodeObjectForKey:#"string1"];
self.string2 = [coder decodeObjectForKey:#"string2"];
return self;
}
- (void)dealloc {
[string1 release];
[string2 release];
[super dealloc];
}
#end
I created an array of these objects like this
MyClass *object1 = [[MyClass alloc] init];
object1.string1 = #"object1 string1";
object1.string2 = #"string1 string2";
MyClass *object2 = [[MyClass alloc] init];
object2.string1 = #"object2 string1";
object2.string2 = #"object2 string2";
theArray = [[NSMutableArray alloc] initWithObjects:object1, object2, nil];
Then I saved the array like this
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:theArray] forKey:#"savedArray"];
Then I loaded the array from disk like this.
NSData *theData = [[NSUserDefaults standardUserDefaults] objectForKey:#"savedArray"];
if (theData != nil) {
NSLog(#"found something");
theArray = [NSMutableArray arrayWithArray:[NSKeyedUnarchiver unarchiveObjectWithData:theData]];
}
The program runs normally without error until it gets to this
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
// ...
// Pass the selected object to the new view controller.
detailViewController.myObject = [theArray objectAtIndex:indexPath.row];
It crashes on that last line. It only crashes if I load the array using NSUserDefaults, however I don't notice anything I did wrong with that part.
When it crashes this is what the debugger says
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSCFString objectAtIndex:]: unrecognized selector sent to instance 0x5955e50'
*** Call stack at first throw:
(
0 CoreFoundation 0x02395919 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x024e35de objc_exception_throw + 47
2 CoreFoundation 0x0239742b -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x02307116 ___forwarding___ + 966
4 CoreFoundation 0x02306cd2 _CF_forwarding_prep_0 + 50
5 custom object array save test 0x00002872 -[RootViewController tableView:didSelectRowAtIndexPath:] + 156
6 UIKit 0x0032b718 -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 1140
7 UIKit 0x00321ffe -[UITableView _userSelectRowAtIndexPath:] + 219
8 Foundation 0x00038cea __NSFireDelayedPerform + 441
9 CoreFoundation 0x02376d43 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 19
10 CoreFoundation 0x02378384 __CFRunLoopDoTimer + 1364
11 CoreFoundation 0x022d4d09 __CFRunLoopRun + 1817
12 CoreFoundation 0x022d4280 CFRunLoopRunSpecific + 208
13 CoreFoundation 0x022d41a1 CFRunLoopRunInMode + 97
14 GraphicsServices 0x02bfa2c8 GSEventRunModal + 217
15 GraphicsServices 0x02bfa38d GSEventRun + 115
16 UIKit 0x002c7b58 UIApplicationMain + 1160
17 custom object array save test 0x00002160 main + 102
18 custom object array save test 0x000020f1 start + 53
19 ??? 0x00000001 0x0 + 1
)
terminate called after throwing an instance of 'NSException'
Edit:
I was able to fix the problem by replacing this line
theArray = [NSMutableArray arrayWithArray:[NSKeyedUnarchiver unarchiveObjectWithData:theData]];
with this liine
theArray = [[NSMutableArray alloc] initWithArray:[NSKeyedUnarchiver unarchiveObjectWithData:theData]];
so I guess the question now is why did that solve the problem?

I don't see anything wrong with your archiving/unarchiving code. I suspect that indexPath.row is out of range.
EDIT after OP edited question:
The error message says: -[NSCFString objectAtIndex:]: unrecognized selector sent to instance 0x5955e50
You'll notice that this means that 'theArray' is actually pointing at an NSString. Somewhere you have assigned the wrong thing to your 'theArray' variable.
EDIT again after another OP edit:
In your original code you had been using alloc/initWithArray: instead of arrayWithArray:.
The arrayWithArray: usage didn't work for you because that method returns an autoreleased object. So by the time you used it later that reference could have been pointing at just about anything, and hence in one case it happened to be pointing at a string.

Related

objc_msgSend crash Objective-C

I got crash report from live user
I have NSObject which has nsstring
#interface MountedVolume : NSObject
#property (nonatomic, strong) NSString *name;
#end
View controller has textfield it values gets changed when notification
received .
#interface ViewController : NSViewController {
MountedVolume *selectedVolume;
__weak IBOutlet NSTextField *txtVolumeName;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserverForName:DCNotificationNameVolumesUpdated object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
dispatch_async(dispatch_get_main_queue(), ^{
//crash report says in this line it got crashed
txtVolumeName.stringValue = selectedVolume.name;
});
}];
}
#end
Below is the crash report any suggestion how to deal with this?
crash report
Crashed: com.apple.main-thread
0 libobjc.A.dylib 0x7fff6ac2639d objc_msgSend + 29
1 AppKit 0x7fff3db3d868 -[NSCell _objectValue:forString:errorDescription:] + 157
2 AppKit 0x7fff3db3d71d -[NSCell setStringValue:] + 40
3 AppKit 0x7fff3db95044 -[NSControl setStringValue:] + 135
4 MyApp 0x104de865b __40-[ViewController viewDidLoad]_block_invoke_3 (ViewController.m:172)
5 libdispatch.dylib 0x7fff6c3ab5f8 _dispatch_call_block_and_release + 12
6 libdispatch.dylib 0x7fff6c3ac63d _dispatch_client_callout + 8
7 libdispatch.dylib 0x7fff6c3b768d _dispatch_main_queue_callback_4CF + 1135
8 CoreFoundation 0x7fff40435f56 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
9 CoreFoundation 0x7fff40435683 __CFRunLoopRun + 2300
10 CoreFoundation 0x7fff40434b35 CFRunLoopRunSpecific + 459
11 HIToolbox 0x7fff3f71396b RunCurrentEventLoopInMode + 292
12 HIToolbox 0x7fff3f7136a5 ReceiveNextEventCommon + 603
13 HIToolbox 0x7fff3f713436 _BlockUntilNextEventMatchingListInModeWithFilter + 64
14 AppKit 0x7fff3daad987 _DPSNextEvent + 965
15 AppKit 0x7fff3daac71f -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1361
16 AppKit 0x7fff3daa683c -[NSApplication run] + 699
17 AppKit 0x7fff3da95d7c NSApplicationMain + 777
18 libdyld.dylib 0x7fff6c3f93d5 start + 1
Looking at the docs, stringValue does not appear to be optional. You do not initialize selectedVolume before viewDidLoad (as far as I can tell) and that means you are likely trying to set this value to nil inside this notification block if it runs before selectedVolume is assigned a value. I would start by trying to set txtVolumeName.stringValue to a hard-coded value first and see if it stops crashing altogether. If it does, you may need to guard against nil values before you call the setter.
e.g.
NSString *string;
NSTextField *textField = [[NSTextField alloc]init];
if (string) {
textField.stringValue = string;
}

My app is crashing due to UITextField text entering procedure

User can tap the next UITextField to enter data or can touch next button on Keyboard.
I have used textFieldShouldReturn method to add text object to array. It works well until I touch next UITextfield to enter data instead of touching next on keyboard and then since no data is added to my array, later in segue, UITableViewController crashes.
Do I need to implement both method or am something wrong here.
ModalViewController.m
#interface ModalViewController (){
NSMutableArray *arrayToReturn;
}
#property (strong, nonatomic) IBOutlet UITextField *bookTextField;
#property (strong, nonatomic) IBOutlet UITextField *pageTextField;
#property (strong, nonatomic) IBOutlet customAddBookButton *doneButton;
#end
#implementation ModalViewController
#pragma mark- textField Delegate
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
NSLog(#"textFieldShouldReturn");
if (textField == self.bookTextField) {
[self.pageTextField becomeFirstResponder];
}else if (textField == self.pageTextField){
if ([self.bookTextField.text isEqual:#""]) {
[self.bookTextField becomeFirstResponder];
}else {
[self.pageTextField resignFirstResponder];
}
}
[arrayToReturn insertObject:self.bookTextField.text atIndex:0];
[arrayToReturn insertObject:self.pageTextField.text atIndex:1];
return YES;
}
#pragma mark- Done button action
- (IBAction)Done:(id)sender {
self.bookMetaReturnedfromModalView (arrayToReturn);
NSLog(#"array is %#", arrayToReturn);
[self dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark- viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
[self.bookTextField becomeFirstResponder];
arrayToReturn = [[NSMutableArray alloc]init];
}
#end
crash log
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 1 beyond bounds for empty array'
*** First throw call stack:
(
0 CoreFoundation 0x000000011089df65 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x0000000110315deb objc_exception_throw + 48
2 CoreFoundation 0x0000000110781a94 -[__NSArrayM objectAtIndex:] + 212
3 BookApp 0x000000010fe0722d -[AddBooksTableViewController tableView:cellForRowAtIndexPath:] + 413
4 UIKit 0x0000000110fc06b3 -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 782
5 UIKit 0x0000000110fc07c8 -[UITableView _createPreparedCellForGlobalRow:willDisplay:] + 74
6 UIKit 0x0000000110f96650 -[UITableView _updateVisibleCellsNow:isRecursive:] + 3187
7 UIKit 0x0000000110fc9595 -[UITableView _performWithCachedTraitCollection:] + 92
8 UIKit 0x0000000110fb19ad -[UITableView layoutSubviews] + 218
9 UIKit 0x0000000110f2211c -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 710
10 QuartzCore 0x000000011547736a -[CALayer layoutSublayers] + 146
11 QuartzCore 0x000000011546bbd0 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 366
12 QuartzCore 0x000000011546ba4e _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 24
13 QuartzCore 0x00000001154601d5 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 277
14 QuartzCore 0x000000011548d9f0 _ZN2CA11Transaction6commitEv + 508
15 QuartzCore 0x000000011548e154 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 92
16 CoreFoundation 0x00000001107c99d7 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
17 CoreFoundation 0x00000001107c9947 __CFRunLoopDoObservers + 391
18 CoreFoundation 0x00000001107bf59b __CFRunLoopRun + 1147
19 CoreFoundation 0x00000001107bee98 CFRunLoopRunSpecific + 488
20 GraphicsServices 0x0000000114f2aad2 GSEventRunModal + 161
21 UIKit 0x0000000110e71676 UIApplicationMain + 171
22 BookApp 0x000000010fe082cf main + 111
23 libdyld.dylib 0x000000011316792d start + 1
24 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
After adding objects to array in textField shouldChangeCharactersInRange method array is being populated simultaneously and everything is working fine.
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (textField == self.bookTextField) {
[arrayToReturn insertObject:[[self.bookTextField text] stringByReplacingCharactersInRange:range withString:string] atIndex:0];
}else if (textField == self.pageTextField){
[arrayToReturn insertObject:[[self.pageTextField text] stringByReplacingCharactersInRange:range withString:string] atIndex:1];
}
return YES;
}

Get web text to Label

I need to get the text from URL http://cast.midiaip.com.br:6530/currentsong?sid=1 and display it in a UILabel
My code is like that:
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (strong, nonatomic) IBOutlet UILabel *musicasLabel;
- (IBAction)textoButton:(id)sender;
#property (strong, nonatomic) IBOutlet UIWebView *webView;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize musicasLabel;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)textoButton:(id)sender {
NSURL *url = [NSURL URLWithString:#"http://cast.midiaip.com.br:6530/currentsong?sid=1"];
NSData *data = [NSData dataWithContentsOfURL:url];
NSString *string = [NSString stringWithUTF8String:[data bytes]];
musicasLabel.text = string;
}
#end
I always get the error:
2015-04-17 02:55:21.637 teste label[14194:797672] ***
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '***
+[NSString stringWithUTF8String:]: NULL cString'
*** First throw call stack:
(
0 CoreFoundation 0x000000010cf1bf35
__exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010cbb4bb7 objc_exception_throw + 45
2 CoreFoundation 0x000000010cf1be6d +[NSException raise:format:] + 205
3 Foundation 0x000000010c719464 +[NSString stringWithUTF8String:] + 78
4 teste label 0x000000010c6885e5 -[ViewController textoButton:] + 181
5 UIKit 0x000000010d3098be -[UIApplication sendAction:to:from:forEvent:] + 75
6 UIKit 0x000000010d410410 -[UIControl _sendActionsForEvents:withEvent:] + 467
7 UIKit 0x000000010d40f7df -[UIControl touchesEnded:withEvent:] + 522
8 UIKit 0x000000010d34f308 -[UIWindow _sendTouchesForEvent:] + 735
9 UIKit 0x000000010d34fc33 -[UIWindow sendEvent:] + 683
10 UIKit 0x000000010d31c9b1 -[UIApplication sendEvent:] + 246
11 UIKit 0x000000010d329a7d _UIApplicationHandleEventFromQueueEvent + 17370
12 UIKit 0x000000010d305103 _UIApplicationHandleEventQueue + 1961
13 CoreFoundation 0x000000010ce51551 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
14 CoreFoundation 0x000000010ce4741d __CFRunLoopDoSources0 + 269
15 CoreFoundation 0x000000010ce46a54 __CFRunLoopRun + 868
16 CoreFoundation 0x000000010ce46486 CFRunLoopRunSpecific + 470
17 GraphicsServices 0x00000001104ea9f0 GSEventRunModal + 161
18 UIKit 0x000000010d308420 UIApplicationMain + 1282
19 teste label 0x000000010c688ae3 main + 115
20 libdyld.dylib 0x000000010f4ab145 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
Thank you very much!!!
You are initializing your string incorrectly. Your question is answered here:
convert UTF-8 encoded NSData to a NSString

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
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.

Cocoa Touch - iPhone App crashes when button is pressed?

This is my first app. It doesn't crash the simulator just brings you back to the home screen. This isn't my first cocoa program (I'm not a pro at cocoa either)just my first iPhone.
It crashes when you press the letsPlayButton, which runs the -(IBAction)letsPlay:(id)sender; method.
Help me! Im so lost with what's wrong!
.H
#import <UIKit/UIKit.h>
#interface BrainiacViewController : UIViewController {
IBOutlet UILabel *theQuestion;
IBOutlet UILabel *theScore;
IBOutlet UILabel *theLives;
IBOutlet UIButton *answerOne;
IBOutlet UIButton *answerTwo;
IBOutlet UIButton *answerThree;
IBOutlet UIButton *answerFour;
IBOutlet UIButton *letsPlayButton;
NSString *questionNumber;
NSInteger myScore;
NSInteger myLives;
NSInteger usersAnswer;
NSArray *theQuiz;
//quiz dictionarys
NSMutableDictionary *question, *rightAnswer, *wrongOne, *wrongTwo, *wrongThree;
}
-(IBAction)buttonOne:(id)sender;
-(IBAction)buttonTwo:(id)sender;
-(IBAction)buttonThree:(id)sender;
-(IBAction)buttonFour:(id)sender;
-(IBAction)letsPlay:(id)sender;
-(void)checkAnswer;
-(void)askQuestion;
-(void)updateScore;
-(void)loadQuiz;
#end
.M
#import "BrainiacViewController.h"
#implementation BrainiacViewController
-(void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
-(IBAction)buttonOne:(id)sender{
usersAnswer = 1;
}
-(IBAction)buttonTwo:(id)sender{
usersAnswer = 2;
}
-(IBAction)buttonThree:(id)sender{
usersAnswer = 3;
}
-(IBAction)buttonFour:(id)sender{
usersAnswer = 4;
}
-(IBAction)letsPlay:(id)sender{
//un hide answer buttons
[answerOne setHidden:NO];
[answerTwo setHidden:NO];
[answerThree setHidden:NO];
[answerFour setHidden:NO];
//hide the lets play button
[letsPlayButton setHidden:YES];
//assign values to variables
myScore = 0;
myLives = 3;
questionNumber = 0;
//ask question and start game
[self askQuestion];
}
-(void)checkAnswer{
[question objectForKey:questionNumber];
[rightAnswer objectForKey:questionNumber];
[wrongOne objectForKey:questionNumber];
[wrongTwo objectForKey:questionNumber];
[wrongThree objectForKey:questionNumber];
}
-(void)askQuestion{
//create array to mix up the possible answers
NSMutableArray *possibleAnswers = [[NSMutableArray alloc] init];
[possibleAnswers addObject:[rightAnswer objectForKey:questionNumber] ];
[possibleAnswers addObject:[wrongOne objectForKey:questionNumber] ];
[possibleAnswers addObject:[wrongTwo objectForKey:questionNumber] ];
[possibleAnswers addObject:[wrongThree objectForKey:questionNumber] ];
//set labels/buttons for question
theQuestion.text = [question objectForKey:questionNumber];
//user picks a answer button and sets a value to usersAnswer
questionNumber = questionNumber + 1;
[self checkAnswer];
}
-(void)updateScore{
}
-(void)loadQuiz{ //assigns dictionary values
//*KEY* defines question number
[question setObject:#"Which is NOT a starwars movie?" forKey:#"1"];
[rightAnswer setObject:#"Attack of the Jedi" forKey:#"1"];
[wrongOne setObject:#"A New Hope" forKey:#"1"];
[wrongTwo setObject:#"The Phantom Menace" forKey:#"1"];
[wrongThree setObject:#"Attack of the Clones" forKey:#"1"];
[question setObject:#"In what state is the majority of Yellow Stone National Park in?" forKey:#"2"];
[rightAnswer setObject:#"Wyoming" forKey:#"2"];
[wrongOne setObject:#"California" forKey:#"2"];
[wrongTwo setObject:#"Ohio" forKey:#"2"];
[wrongThree setObject:#"Nebraska" forKey:#"2"];
[question setObject:#"In the US, what household pet is the most common?" forKey:#"2"];
[rightAnswer setObject:#"Dogs" forKey:#"2"];
[wrongOne setObject:#"Cats" forKey:#"2"];
[wrongTwo setObject:#"Hamsters" forKey:#"2"];
[wrongThree setObject:#"Komodo Dragons" forKey:#"2"];
[question setObject:#"A plane is traveling 2675 miles every 5 hours. How fast is the plane going in Miles per Hour?" forKey:#"3"];
[rightAnswer setObject:#"535 Mph" forKey:#"3"];
[wrongOne setObject:#"325 Mph" forKey:#"3"];
[wrongTwo setObject:#"535 Mph" forKey:#"3"];
[wrongThree setObject:#"420 Mph" forKey:#"3"];
}
#end
appdelagate.h
#import <UIKit/UIKit.h>
#class BrainiacViewController;
#interface BrainiacAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
BrainiacViewController *viewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet BrainiacViewController *viewController;
#end
appdelegate.m
#import "BrainiacAppDelegate.h"
#import "BrainiacViewController.h"
#implementation BrainiacAppDelegate
#synthesize window;
#synthesize viewController;
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Add the view controller's view to the window and display.
[window addSubview:viewController.view];
[window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
/*
Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
*/
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
/*
Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
If your application supports background execution, called instead of applicationWillTerminate: when the user quits.
*/
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
/*
Called as part of transition from the background to the inactive state: here you can undo many of the changes made on entering the background.
*/
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
/*
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
*/
}
- (void)applicationWillTerminate:(UIApplication *)application {
/*
Called when the application is about to terminate.
See also applicationDidEnterBackground:.
*/
}
#pragma mark -
#pragma mark Memory management
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
/*
Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later.
*/
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
#end
I tried it again and checked the console and the error was this..I dont know what that means.
[Session started at 2010-07-11 12:24:40 -0400.]
2010-07-11 12:24:45.729 Brainiac[46764:207] -[NSCFString letsPlay:]: unrecognized selector sent to instance 0x5944f00
2010-07-11 12:24:45.733 Brainiac[46764:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSCFString letsPlay:]: unrecognized selector sent to instance 0x5944f00'
*** Call stack at first throw:
(
0 CoreFoundation 0x02395919 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x024e35de objc_exception_throw + 47
2 CoreFoundation 0x0239742b -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x02307116 ___forwarding___ + 966
4 CoreFoundation 0x02306cd2 _CF_forwarding_prep_0 + 50
5 UIKit 0x002b9e14 -[UIApplication sendAction:to:from:forEvent:] + 119
6 UIKit 0x003436c8 -[UIControl sendAction:to:forEvent:] + 67
7 UIKit 0x00345b4a -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 527
8 UIKit 0x003446f7 -[UIControl touchesEnded:withEvent:] + 458
9 UIKit 0x002dd2ff -[UIWindow _sendTouchesForEvent:] + 567
10 UIKit 0x002bf1ec -[UIApplication sendEvent:] + 447
11 UIKit 0x002c3ac4 _UIApplicationHandleEvent + 7495
12 GraphicsServices 0x02bfbafa PurpleEventCallback + 1578
13 CoreFoundation 0x02376dc4 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 52
14 CoreFoundation 0x022d7737 __CFRunLoopDoSource1 + 215
15 CoreFoundation 0x022d49c3 __CFRunLoopRun + 979
16 CoreFoundation 0x022d4280 CFRunLoopRunSpecific + 208
17 CoreFoundation 0x022d41a1 CFRunLoopRunInMode + 97
18 GraphicsServices 0x02bfa2c8 GSEventRunModal + 217
19 GraphicsServices 0x02bfa38d GSEventRun + 115
20 UIKit 0x002c7b58 UIApplicationMain + 1160
21 Brainiac 0x00002790 main + 102
22 Brainiac 0x00002721 start + 53
)
terminate called after throwing an instance of 'NSException'
I tried it again and checked the console and the error was this..I dont know what that means.
2010-07-11 12:24:45.729 Brainiac[46764:207] -[NSCFString letsPlay:]: unrecognized selector sent to instance 0x5944f00
You sent a message (letsPlay:) to an object that does not respond to that message (an NSString, shown here as NSCFString).
This sort of thing usually happens because you didn't properly hold on to the object that you meant to send letsPlay: to, so it got deallocated. An NSString later got allocated at the same address, so everything that had been holding the pointer to the old object (and thinks it still is) is now holding the pointer to the NSString. Same pointer, different object. Then, when one of those would-be owners tries to send the message to the object it thinks it still has… boom.
The fix is to check your ownerships and make sure you're retaining (or creating using alloc and not autoreleasing) what you mean to own.
On a related note:
NSMutableArray *possibleAnswers = [[NSMutableArray alloc] init];
[possibleAnswers addObject:[rightAnswer objectForKey:questionNumber] ];
[possibleAnswers addObject:[wrongOne objectForKey:questionNumber] ];
[possibleAnswers addObject:[wrongTwo objectForKey:questionNumber] ];
[possibleAnswers addObject:[wrongThree objectForKey:questionNumber] ];
If you mean for this to be a local variable, you must release it by the end of the method, or you will leak this array.
If you mean to own this object, you should move it to an instance variable, and drop the local variable, and continue creating the object as you are doing now.
Required reading: The Memory Management Programming Guide for Cocoa.
You need to 'box' the integer questionNumber in a NSNumber object, like this:
theQuestion.text = [question objectForKey:[NSNumber numberWithInt:questionNumber]];
Or, you can use the more appropriate NSArray indexer:
theQuestion.text = [question objectAtIndex:questionNumber];