The first few programs I wrote in ObjC worked but were a cluttered mess so this time I wanted to do it right and employ MVC. All of the pieces work and have been tested and things were going great until I tried to copy an NSMutableArray from the model through the VC to the view. The exact same format and code was used and works fine in another aspect of the program but this particular view uses drawRect and breaks if I don't retain the array. When I do it causes a leak. To isolate the problem and create a workaround I ended up loading the array directly from the pList. It looks like this:
#interface HWView : UIView <UIGestureRecognizerDelegate>
{
NSMutableArray *drawStates;
}
#property (nonatomic, retain) NSMutableArray *drawStates;
in the .m
#implementation HWView
#synthesize drawStates;
- (void)awakeFromNib
{
[self HWVReset];
}
-(void)HWVReset
{
NSLog(#"HWVReset:");
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *plistPath = [documentsDirectorystringByAppendingPathComponent: #"PLIST_drawState.plist"];
self.drawStates = [[NSMutableArray arrayWithContentsOfFile:plistPath]retain];
NSLog(#"drawStates:%#",self.drawStates);
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect
{
//draw code
}
- (void)dealloc
{
[self.drawStates release];
[super dealloc];
}
So this runs but it leaks. I remove the retain from: "self.drawStates = [[NSMutableArray arrayWithContentsOfFile:plistPath]retain];" and it crashes. Any help is appreciated.
Of course : [NSArray array] is an autoreleased object. So you'll be calling a deallocated object. Read about Autorelease in Apple's docs.
Related
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.
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.