Objective-C NSMutableArray Count Causes EXC_BAD_ACCESS - objective-c

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.

Related

Issue adding to NSMutableArray

I have looked all over the place for anyone who has experienced this issue but have yet to find anything relevant, so I thought I'd ask it myself...
I have a custom object (HitterData) which I will use to populate cells in a UITableView, then two ViewControllers (one is hitterTableViewController, the other is a "detail" view controller labeled "AddPlayerViewController").
The problem is that I can add HitterData objects to the NSMutableArray in my Table VC, but only one, and then when I add another one using the detail view controller, the Mutable array is "reinitialized" and I can again only have one object at a time.
HitterObject:
#implementation HitterData.m
#synthesize hitterName = _hitterName;
#synthesize position = _position;
-(id)initWIthNameAndPosition:(NSString *)hitterName position:(NSString *)position {
if ((self = [super init])) {
self.hitterName = _hitterName;
self.position = _position;
}
return self;
}
HitterTableViewController.h
#import "HitterData.h"
#import "HitterDoc.h"
#import "AddPlayerViewController.h"
#interface HitterTableViewController : UITableViewController
#property (nonatomic, strong) NSMutableArray *hitters;
- (IBAction)backButton:(id)sender;
- (IBAction)addPlayerView:(id)sender;
-(void)addHitterObject:(HitterData *)hitter;
HitterTableViewController.m (only relevant to make this more readable)
#implementation HitterTableViewController
#synthesize hitters = _hitters;
- (void)viewDidLoad {
[super viewDidLoad];
self.hitters = [NSMutableArray array];
}
-(void)addHitterObject:(HitterData *)hitter {
if(_hitters != nil) {
[_hitters addObject:hitter];
} else {
_hitters = [NSMutableArray array];
[_hitters addObject:hitter];
NSLog(#"MutableArray is not valid");
}
}
AddPlayerViewController.h
#interface AddPlayerViewController : UIViewController <UITextFieldDelegate, UINavigationControllerDelegate>
#property (weak, nonatomic) IBOutlet UITextField *nameTextField;
#property (weak, nonatomic) IBOutlet UITextField *positionTextField;
#property (nonatomic) HitterTableViewController *hitterTable;
#property (nonatomic) NSString *hitterName;
#property (nonatomic) NSString *position;
//-(void)addNewHitterToHittersArray:(HitterData *)hitter;
- (IBAction)addPlayerToRoster:(id)sender;
AddPlayerViewController.m
#implementation AddPlayerViewController
#synthesize hitterTable;
- (void)viewDidLoad {
[super viewDidLoad];
hitterTable = [[HitterTableViewController alloc] init];
}
- (IBAction)addPlayerToRoster:(id)sender {
self.hitterName = [self.nameTextField text];
self.position = [self.positionTextField text];
HitterData *hitter = [[HitterData alloc] init];
hitter.hitterName = self.hitterName;
hitter.position = self.position;
[hitterTable addHitterObject:hitter];
ArraySingleton *arrayS = [[ArraySingleton alloc] init];
[arrayS initializeArray];
[arrayS addToHittersArray:hitter];
if (arrayS) {
NSLog(#"arrayS exists in AddPlayerVC");
} else {
NSLog(#"arrayS does not exist");
}
[self performSegueWithIdentifier:#"backToTeamTableViewController" sender:self];
}
Am I missing something here?
Guess based just on the code shown:
Every time you wish to add a player it looks like you create a new AddPlayerView/AddPlayerViewController. In turn that controller creates, in its viewDidLoad, a new HitterTableViewController - which of course has its own empty array. The code should instead be referencing the existing HitterTableViewController.
BTW: The common design pattern is MVC - model, view, controller - consider whether you are in your current situation because you've stored part of your model, the array, in your controller, and maybe both controllers should be referencing a common shared model object containing that array.
BTW: All those #synthesise statements are unneeded. In modern Obj-C synthesis is automatic and you rarely need these statements. Also it is generally recommended to not use the property backing variable directly, and certainly not when storing into the property as this breaks KVO. (There also appears to be a related typo in HitterData.m but as you don't report that as not working it is probably just a typo in your question and not code.)
HTH
AddPlayerViewController should know nothing about HitterTableViewController, return the new HitterData object with a delegate method.
- (IBAction)addPlayerToRoster:(id)sender
{
Hitter *hitter = [[Hitter alloc] init];
hitter.name = [self.nameTextField text];
hitter.position = [self.positionTextField text];
[self.delegate didAddHitter:hitter];
}
Then back in HitterTableViewController
- (void)didAddHitter:(Hitter *)hitter
{
[self.hitters addHitter:hitter];
[self dismissViewControllerAnimated:YES completion:nil];
}

Why need I add self when assign attibute for one model?

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.

Array loses all values after go trough its own method - Objective C

I have this piece of code below and I'm trying to add Objects(String elements) to an array, problem is that every time I'm out its adding's method, it goes to nil, it doesn't retain the objects.
I know I'm doing wrong, even that I already tried lot of combinations and variations, even with my own constructor _MyArray etc etc, same result... it works, but not further...
Could you help me please?
#interface ArraysModel()
#property (nonatomic, retain) NSMutableArray *MyArray;
#end
#implementation ArraysModel
#synthesize MyArray;
-(void)AddObjectToTheList:(NSString *)object {
if(!MyArray) MyArray = [[NSMutableArray alloc] init];
[MyArray addObject:object];
NSLog(#"%#",self.MyArray);
NSLog(#"Object added %u",[self.MyArray count]);
}
-(NSMutableArray *)ObjectList {
return self.MyArray;
NSLog(#"%#",self.MyArray);
NSLog(#"Object added %u",[self.MyArray count]);
}
#end
The header is like this:
#interface ArraysModel : NSObject
-(void)AddObjectToTheList:(NSString *)object;
And here is my call from my ViewController:
- (IBAction)AddToTheList {
ArraysModel *MyObjectToAdd = [[ArraysModel alloc] init];
[MyObjectToAdd AddObjectToTheList:TextArea.text];
[self.view endEditing:YES];
Well, there's your problem -- you're alloc init'ing a new instance of ArraysModel, and therefore a new array with every call. You need to create a strong reference to your instance, and check for whether it exits, and only init if it doesn't.
In the .h:
#property (strong, nonatomic) ArraysModel *myObjectToAdd;
in the .m:
-(IBAction)AddToTheList {
if (! self.myObjectToAdd) {
self.myObjectToAdd = [[ArraysModel alloc] init];
}
[self.myObjectToAdd AddObjectToTheList:TextArea.text];
[self.view endEditing:YES]
}

NSMutableArray as instance variable alway null

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.

Using initWithObjects: causes crash, but initWithCapacity: followed by addObject: does not

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.