I have declared a property NSMutableArray in the header file. Then I alloc, init it in the viewDidLoad method. But when I try to add an object to the array in a different method it keeps returning (null). Am I doing some obvious mistake? Please ask if you want to see some more code.
.h
#property (strong, nonatomic) NSMutableArray *myList;
.m
- (void)viewDidLoad
{
self.dataController = [[DataController alloc]init];
self.myList = [[NSMutableArray alloc] init];
[super viewDidLoad];
}
[...]
NSDictionary *myObject = [self.dataController.objectList objectAtIndex:r];
[[cell textLabel]setText:[myObject objectForKey:#"title"]];
[self.myList addObject:myObject];
NSLog(#"myList %#",self.myList);
NSLog(#"myObject %#",myObject);
The output prints myObject but self.myList keeps returning (null). Appreciate all help!
Edit: Fixed, thank you for your answers!
Not sure where you are using this array. If you have to use this array before viewDidLoad is called, you can do it as,
NSDictionary *myObject = [self.dataController.objectList objectAtIndex:r];
[[cell textLabel]setText:[myObject objectForKey:#"title"]];
if (!self.myList)
self.myList = [[NSMutableArray alloc] init];//for the first time, this will initialize
[self.myList addObject:myObject];
Since you are using [cell textLabel] I am assuming that you are doing this in one of the table view delegates. In that case check if you are setting self.myList = nil; any where in the class.
In your posted code i see no error.
Set a breakpoint and look if the code where you init the array is called first.
I bet that viewDidLoad hasn't been called yet when the NSLogs are execute.
To ensure that the array has been initialized, try putting the initialization in your init method.
Related
In my prepareForSegue method, I pass an immutable array retrieved from NSUserDefaults to a DetailViewController mutable dictionary property. Do I need to create a mutable copy of the array before I modify it or does that happen automatically in the NSMutableDictionary class setter method?
My code...
ViewController.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"EditReminder"])
{
UINavigationController *navigationController = segue.destinationViewController;
DetailViewController *detailViewController = [[navigationController viewControllers] objectAtIndex:0];
detailViewController.delegate = self;
[detailViewController setTitle:#"Edit Reminder"];
// Pass ReminderData to detailVC if editing
NSIndexPath *selectedRowIndex = [self.tableView indexPathForSelectedRow];
NSArray *remindersArray = [[NSUserDefaults standardUserDefaults] objectForKey:#"reminders"];
detailViewController.reminderData = [remindersArray objectAtIndex: selectedRowIndex.row];
}
}
DetailViewController.h
#property (strong, nonatomic) NSMutableDictionary *reminderData;
DetailViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
if (self.reminderData) {
// Reminder data from user defaults is immutable. Create mutable copy.
// Is this necessary?
self.reminderData = [self.reminderData mutableCopy];
}
else {
self.reminderData = [[NSMutableDictionary alloc] init];
}
}
You need to create the mutable copy, but your implementation is wrong.
In prepareForSegue, you need to do the mutableCopy, or you already have a wrong object stored in your property. There is no reason to do that in viewDidLoad, and it can be considered a bug.
Yes, you definitely need to create a mutable copy as you've illustrated here. The compiler might not complain if you assign an instance of NSDictionary (immutable) to an NSMutableDictionary-valued property, but calling any of the mutating methods on the stored object will cause a runtime exception. There's no magic in the language or framework that makes an immutable collection assigned to a mutable-typed variable automatically mutable.
Also, as noted in another answer, you should perform the mutable copy when you assign the property for the first time (in prepareForSegue), rather than at a later time.
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.
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'm trying to simply add objects to a mutable array but they WILL NOT insert. I'm not getting errors or anything and I can't figure out whats going on.
In my main delegate file I split an array into 4 separate strings like so.
NSArray *split=[currentParsedCharacterData componentsSeparatedByString:#"|"];
NSLog([split objectAtIndex:3]);
NSString *date=[split objectAtIndex:0];
NSString *venue=[split objectAtIndex:1];
NSString *event=[split objectAtIndex:2];
NSString *city=[split objectAtIndex:3];
I've traced out the string values and they are definitely there.
Up next I try to add these string values to mutable arrays
[self.promoTabOptionEvents.dates addObject:date];
[self.promoTabOptionEvents.venues addObject:venue];
[self.promoTabOptionEvents.event addObject:event];
[self.promoTabOptionEvents.city addObject:city];
When I check the arrays in the debugger they are empty. What am I doing wrong?
promoTabOptionEvents class looks like this
import
#interface PromoTabOptionEvents : UIViewController {
NSString *event_headline;
NSMutableArray *dates;
NSMutableArray *venues;
NSMutableArray *event;
NSMutableArray *city;
}
#property(nonatomic,retain)NSString *event_headline;
#property(nonatomic,retain)NSMutableArray *dates;
#property(nonatomic,retain)NSMutableArray *venues;
#property(nonatomic,retain)NSMutableArray *event;
#property(nonatomic,retain)NSMutableArray *city;
-(void)applyLabels;
-(id)initWithTabBar;
#end
#import "PromoTabOptionEvents.h"
#implementation PromoTabOptionEvents
#synthesize event_headline;
#synthesize dates;
#synthesize venues;
#synthesize event;
#synthesize city;
-(id) initWithTabBar {
if ([self init]) {
//this is the label on the tab button itself
//self.title = #"Tab1";
//use whatever image you want and add it to your project
self.tabBarItem.image = [UIImage imageNamed:#"events.png"];
// set the long name shown in the navigation bar
self.navigationItem.title=#"Events";
CGRect bgframe;
bgframe.size.width=320; bgframe.size.height=460;
bgframe.origin.x=0; bgframe.origin.y=0;
UIImage* bgimage = [UIImage imageNamed:#"eventsbig.png"];
UIImageView *imagebgview = [[UIImageView alloc] initWithImage: bgimage];
imagebgview.frame=bgframe;
imagebgview.contentMode=UIViewContentModeScaleAspectFit;
self.view.backgroundColor=[UIColor whiteColor];
[self.view addSubview:imagebgview];
}
return self;
}
Can you add the code where you initialize your NSMutableArray instances? I think you might have forgotten to initialise the arrays and your addObject calls are being swallowed up with no effect.
Are you instantiating the properties anywhere, and if so, have you debugged through to verify that is the case? Otherwise you may be sending messages to nil, which will have no effect. Alternatively, you may be doing the array creation after this call, which would make it look like they're not added.