After many hours wasted, I officially turn to the experts for help!
My problem lies with using a NSMutableArray as an instance variable, and trying to both add objects and return the array in a method in my class. I am obviously doing something fundamentally wrong and would be grateful for help...I have already tried all the suggestions from other similar questions on stackoverflow, read apples documentation, and basically all combinations of trial and error coding I can think of. The mutable array just alway returns (null). I've even tried creating properties for them, but still the array returns (null) and then I also am running into memory management problems due to the retain while setting the property, and the init in the init method for the class.
Here is what I am trying to do:
1) Loop through a series of UISwitches and if they are 'switched on', add a string to the NSMutableArray
2) Assign this mutable array to another array in another method
Any help much appreciated,
Andy
And for some code...
fruitsViewController.h
#import <UIKit/UIKit.h>
#interface fruitsViewController : UIViewController
{
NSMutableArray *fruitsArr;
UISwitch *appleSwitch;
UISwitch *orangeSwitch;
}
#property (nonatomic,retain) NSMutableArray *fruitsArr; // ADDED ON EDIT
#property (nonatomic,retain) IBOutlet UISwitch *appleSwitch;
#property (nonatomic,retain) IBOutlet UISwitch *orangeSwitch;
- (IBAction)submitButtonPressed:(id)sender;
#end
fruitsViewController.m
#import "fruitsViewController.h"
#implementation fruitsViewController
#synthesize fruitsArr; // ADDED ON EDIT
#synthesize appleSwitch, orangeSwitch;
/* COMMENTED OUT ON EDIT
-(id)init
{
if (self = [super init]) {
// Allocate memory and initialize the fruits mutable array
fruitsArr = [[NSMutableArray alloc] init];
}
return self;
}
*/
// VIEW DID LOAD ADDED ON EDIT
- (void)viewDidLoad
{
self.fruitsArr = [[NSMutableArray alloc] init];
}
- (void)viewDidUnload
{
self.fruitsArr = nil;
self.appleSwitch = nil;
self.orangeSwitch = nil;
}
- (void)dealloc
{
[fruitsArr release];
[appleSwitch release];
[orangeSwitch release];
[super dealloc];
}
- (IBAction)submitButtonPressed:(id)sender
{
if ([self.appleSwitch isOn]) {
[self.fruitsArr addObject:#"Apple"; // 'self.' ADDED ON EDIT
}
if ([self.orangeSwitch isOn]) {
[self.fruitsArr addObject:#"Orange"; // 'self.' ADDED ON EDIT
}
NSLog(#"%#",self.fruitsArr); // Why is this returning (null) even if the switches are on?!
[fruitsArr addObject:#"Hello World";
NSLog(#"%#",self.fruitsArr); // Even trying to add an object outside the if statement returns (null)
}
#end
It seems like your init function is never called. If you're initializing this view controller from a NIB, you need to use initWithCoder. If not, just declare your fruitsArr in viewDidLoad.
Use view did load instead of init...
- (void)viewDidLoad
{
fruitsArr = [[NSMutableArray alloc] init];
}
Change that init for viewDidLoad and see what happens
Is your init method ever being called (in complicationsViewController). Add a NSLog to check this, you might be calling initWithNib: maybe.
At viewDidUnload you should remove self.fruitsArr = nil;, or, if you want to keep it, then initialize the fruitsArr in viewDidLoad (and remove it from init).
because fruitsArr don't be init.
you should do this first:
fruitsArr = [[NSMutableArray alloc] init];
so, I think you don't run - (id)init before you use fruitsArr.
Related
I have one model.
I want to update one attribute each 3 seconds after init, and I need to change the attribute in one other view controller later.
the code is:
MODEL
#interface Ap : NSObject
#property (nonatomic, retain) NSString *address;
#property (nonatomic, retain) NSString *sessionId;
+ (id)sharedInstance;
#end
#implementation Ap
#synthesize sessionId, address;
-(id) init {
if (self = [super init]) {
self.address = nil;
self.sessionId = nil;
[NSTimer scheduledTimerWithTimeInterval:3 target:self selector:#selector(heartbeat) userInfo:nil repeats:YES];
}
return self;
}
-(void) updateSession{
sessionId = #"some string";
}
- (void) update{
self.sessionId = #"some value from network";
}
+ (Ap *)sharedInstance {
if (!sharedInstance) {
sharedInstance = [[super allocWithZone:NULL] init];
}
return sharedInstance;
}
#end
CONTROLLER
- (void) viewDidLoad {
[super viewDidLoad];
[[Ap sharedInstance] updateSession];
}
The error is: (lldb) bad access when model update
And I change the updateSession method to
-(void) updateSession{
self.sessionId = #"some string";
}
The error is gone, can anyone tell me why?
You should use self.ap = [[Ap alloc] init]; in your app delegate. Your model object might be getting released when you try to call update on that which might cause a crash.
Your code will look like this,
#interface SomeAppDelegate : UIResponder{
#property(nonatomic, retain) Ap *ap; //declare property here
#end
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if(!self.ap){
self.ap = [[Ap alloc] init]; //use property here as self.ap which will retain ap. Otherwise it will not retain it.
}
}
Update:
Looks like you have removed the previous question and added a completely new question to the previous one. Anyways I will try to answer this one as well.
The error is gone, can anyone tell me why?
The reason is same as what I mentioned above. If you use self.sessionId = #"some string";, you are retaining the object. Because it is a property and a property will internally retain since you have declared that property as retain. But if you use sessionId = #"some string";, its scope is only inside that method since you are not using the property. You are directly setting the value without calling property and it will autoreleased after that method. And hence you will get a bad access.
I would suggest you to go through the apple documentation to understand more about properties and its working.
A really strange problem. I have to init an array in - (void)viewDidLoad.
The array, prjMemberArray is declared as a property:
#property(nonatomic, retain) NSMutableArray* prjMemberArray;
If I use this
prjMemberArray = [[NSMutableArray alloc] initWithObjects:#"someone",#"someone",#"someone" ,nil];
with release called in viewDidUnload,
then when the view loaded , it will crashes immediately But when I use this:
prjMemberArray = [[NSMutableArray alloc] initWithCapacity:0];
[prjMemberArray addObject:#"someone"];
it works well. Can anyone explain this? I use a storyboard to present the current view controller, like this:
UIStoryboard* sb = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
prj_Detail = [sb instantiateViewControllerWithIdentifier:#"ProjectDetailVC"];
[self presentModalViewController:prj_Detail animated:YES];
Where prjMemberArray is a property of prj_Detail.
Are you sure you have not misspelled items and written e.g. "someone" instead of #"someone" in the crashing scenario?
Don't forget to use self when referring to properties. Here's the a safe way to declare that without having to worry about leaks:
Header:
#property(nonatomic, retain) NSMutableArray* prjMemberArray;
Implementation:
#synthesize prjMemberArray=_prjMemberArray;
- (void) viewDidLoad {
[super viewDidLoad];
NSMutableArray *prjMemberArray = [[NSMutableArray alloc] initWithObjects:#"someone", #"someone", #"someone" ,nil];
self.prjMemberArray = prjMemberArray;
[prjMemberArray release];
}
- (void) dealloc {
[_prjMemberArray release];
[super dealloc];
}
#property creates the getter and setter for your variable but is often confused for a variable itself. When they released XCode4 I believe they added the ability to set what you want the instance variable to be named by doing:
#synthesize prjMemberArray=_prjMemberArray;
Before XCode4 you simply did:
#synthesize prjMemberArray;
So what #property is doing behind the scenes is a little something like this:
-(NSMutableArray*) prjMemberArray {
return _prjMemberArray;
}
-(void) setPrjMemberArray:(NSMutableArray *) val {
if( _prjMemberArray != nil )
[prjMemberArray release];
_prjMemberArray = [val retain];
}
So don't think of #property as a variable itself and remember to always use self when referring to them. That should save you a lot of pain and a few memory leaks as well.
I am semi-new to Objective-c and confused with why my NSMutableDictionary is not retaining information. I am declaring my variable in the header file:
#interface view_searchResults : UIViewController <UITableViewDataSource, UITableViewDelegate> {
NSMutableDictionary *imageDicationary;
}
#property (nonatomic, retain) NSMutableDictionary *imageDictionary;
Then in my .m file, I have the following:
#synthesize imageDictionary;
-(UIImage *)getImageForURL:(NSURL*)url {
UIImage*image;
image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
[imageDictionary setObject:image forKey:#"test"];
if([imageDictionary objectForKey:#"test"]){
NSLog(#"Exists");
}
}
There is obviously other code to support this, but I can confirm that a URL is being passed, and the file is downloading correctly elsewhere. Also, I can confirm that this function is being executed, and I am not referring to the NSMutableDictionary anywhere else in the document.
Thanks!
Where do you create your NSMutable dictionary? If this really is all the code you have you need to create the dictionary:
#implementation view_searchResults
- (id) init;{
self = [super init];
if(self) {
imageDicationary = [NSMutableDictionary alloc] init]; // should also be released in dealloc.
}
return self;
}
If this is the error then the reason you are not causing a crash is because in objective-C it is valid to send a message to the nil object - it just does nothing.
You havent told us whether the "Exists" NSLog is executed, you also are NOT returning the image.
In other words, I fail to see your problem
Has imageDictionary been initialized? (alloc/init?)
I've been stuck on this for days and each time I come back to it I keep making my code more and more confusing to myself, lol. Here's what I'm trying to do. I have table list of charges, I tap on one and brings up a model view with charge details. Now when the model is presented a object is created to fetch a XML list of users and parses it and returns a NSMutableArray via a custom delegate. I then have a button that presents a picker popover, when the popover view is called the user array is used in an initWithArray call to the popover view. I know the data in the array is right, but when [pickerUsers count] is called I get an EXC_BAD_ACCESS. I assume it's a memory/ownership issue but nothing seems to help. Any help would be appreciated.
Relevant code snippets:
Charge Popover (Charge details model view):
#interface ChargePopoverViewController .....
NSMutableArray *pickerUserList;
#property (nonatomic, retain) NSMutableArray *pickerUserList;
#implementation ChargePopoverViewController
#synthesize whoOwesPickerButton, pickerUserList;
- (void)viewDidLoad {
JEHWebAPIPickerUsers *fetcher = [[JEHWebAPIPickerUsers alloc] init];
fetcher.delegate = self;
[fetcher fetchUsers];
}
-(void) JEHWebAPIFetchedUsers:(NSMutableArray *)theData {
[pickerUserList release];
pickerUserList = theData;
}
- (void) pickWhoPaid: (id) sender {
UserPickerViewController* content = [[UserPickerViewController alloc] initWithArray:pickerUserList];
UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:content];
[popover presentPopoverFromRect:whoPaidPickerButton.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
content.delegate = self;
}
User Picker View Controller
#interface UserPickerViewController .....
NSMutableArray *pickerUsers;
#property(nonatomic, retain) NSMutableArray *pickerUsers;
#implementation UserPickerViewController
#synthesize pickerUsers;
-(UserPickerViewController*) initWithArray:(NSMutableArray *)theUsers {
self = [super init];
if ( self ) {
self.pickerUsers = theUsers;
}
return self;
}
- (NSInteger)pickerView:(UIPickerView *)thePickerView numberOfRowsInComponent:(NSInteger)component {
// Dies Here EXC_BAD_ACCESS, but NSLog(#"The content of array is%#",pickerUsers); shows correct array data
return [pickerUsers count];
}
I can provide additional code if it might help. Thanks in advance.
You declare the ivar holding the array as this...
#property (nonatomic, retain) NSMutableArray *pickerUserList;
But then you have a method implemented like this:
-(void) JEHWebAPIFetchedUsers:(NSMutableArray *)theData {
[pickerUserList release];
pickerUserList = theData;
}
You aren't retaining theData and you aren't calling the synthesized setter. If you did Build and Analyze, it should catch this problem and tell you about it. If not, file a bug.
I am using the iPhone SDK and have an issue doing something simple. I am trying to add an NSNumber object to an NSMutableArray instance variable. I tried adding NSNumber card to NSMutableArray viewedCardsArray, however without breaking, it does not get added to the array. Here is the code.
/////////////////////////////////////////////////////
// Inside the header file Class.h
#interface MyViewController : UIViewController {
NSMutableArray *viewedCardsArray;
//snip ...
}
#property (nonatomic, retain) NSMutableArray *viewedCardsArray;
#end
/////////////////////////////////////////////////////
// Inside the methods file Class.m
#import "StudyViewController.h"
#implementation StudyViewController
#synthesize viewedCardsArray
//snip ...
- (IBAction)doShowCard {
//snip ...
NSNumber *cardIdObject = [[NSNumber alloc] initWithInt:(int)[self.currentCard cardId]];
[viewedCardsArray addObject: cardIdObject];
[cardIdObject release];
}
So this code executes, and does not seem to leak (according to the Leaks performance tool). However when stepping through the code, at no point does CardIdObject appear in viewedCardsArray.
Looking through SO, I know these basic questions are pretty common to ObjC newbies (like me) so apologies in advance!
Have you initialized your viewedCardsArray? If not you need to somewhere - this is usually done in the init method for your class:
- (id)init
{
self = [super init];
if(self) {
viewedCardsArray = [[NSMutableArray alloc] init];
}
return self;
}
Then it is released in the dealloc method:
- (void)dealloc
{
[viewedCardsArray release];
[super dealloc];
}
Perspx has outlined one way of initializing the array. However, you can also use the class methods provided by NSArray:
self. viewedCardsArray = [NSMutableArray array];
This can go in init or elsewhere.
Note: The object will be autoreleased.