NSArray is getting an EXC_BAD_ACCESS - iphone

I'm not entirely sure if I wrote this array correct in the first place. Here is the .h in my app delegate.
NSString *text0;
...
NSString *text123;
NSMutableArray *fortunesArray;
}
#property(nonatomic,retain) NSMutableArray *fortunesArray;
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet AppViewController *viewController;
#end
Then in the app delegate.m I'm assigning all of them like such.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
text0 = #"Text here";
...
text123 = #"Text here";
self.fortunesArray = [NSMutableArray arrayWithObjects:text0,text1,text2,text3,text4,text5,text6,text7,text8,text9,text10,text11,text12,text13,text14,text15,text16,text17,text18,text19,text20,text21,text22,text23,text24,text25,text26,text27,text28,text29,text30,text31,text32,text33,text34,text35,text36,text37,text38,text39,text40,text41,text42,text43,text44,text45,text46,text47,text48,text49,text50,text51,text52,text53,text54,text55,text56,text57,text58,text59,text60,text61,text62,text63,text64,text65,text66,text67,text68,text69,text70,text71,text72,text73,text74,text75,text76,text77,text78,text79,text80,text81,text82,text83,text84,text85,text86,text87,text88,text89,text90,text91,text92,text93,text94,text95,text96,text97,text98,text99,text100,text101,text102,text103,text104,text105,text106,text107,text108,text109,text110,text111,text112,text113,text114,text115,text116,text117,text118,text119,text120,text121,text122,text123,nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
I have tried this with NSArray and Mutable. The EXC_BAD_ACCESS is showing up pointing at text3 and before it was pointing at text5. If I cut out everything after about 50 the screen will open but when I finally try to have it work by clicking the button it resorts back to that bad access. (So can't tell if there is an issue with the views button yet because this issue is happening at this array repeatedly.) I'll post the code that calls it, but I'm pretty sure the main issue has something to do with this array.
In my view controller.m
-(IBAction)ganjaButton:(id)sender{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
int pressCount;
NSString *display;
if(pressCount%2==0){
[sender setBackgroundImage:[UIImage imageNamed:#"nug2.png"] forState:UIControlStateNormal];
display = [[NSString alloc] initWithFormat:#"%#",[appDelegate.fortunesArray objectAtIndex:40]];
}
else{
[sender setBackgroundImage:[UIImage imageNamed:#"nug1.png"] forState:UIControlStateNormal];
display = [[NSString alloc] initWithFormat:#"%#",[appDelegate.fortunesArray objectAtIndex:44]];
}
pressCount++;
label.text = display;
[display release];
}
Also yes in the above code the part that says AppDelegate is actually my AppDelagtes name.
Any help would be appreciated. Thanks.

Have you thought about storing all those text values in a plist and loading them into an array with [NSArray arrayWithContentsOfFile:filePath];?
That would be a MUCH cleaner solution in the first place.
Edit: To get the filePath, assuming your plist is named "textStrings.plist" you would use the following:
NSString *filePath = [bundle pathForResource:#"textStrings" ofType:#"plist"];

Try this:
self.fortunesArray = [NSMutableArray arrayWithObjects:text0, text1, text2, nil];
I don't know if there's a maximum number of parameters that you can pass into a method, but if there is it's likely that you're exceeding that limit at 124, and probably also at 50. If everything works fine when you pass just a few objects into the array, you should just find a different way to create the array. Another answer mentions using a property list, which would be a fine solution. You could also use a plain old text file with some delimiter between strings, read that into a single string, and use NSString's -componentsSeparatedByString: method to create an array.
On the other hand, if you still have trouble with just a few objects in the array, you'll know that the problem lies elsewhere. I don't see any obvious problems, but I'd be on the lookout for other places in your code where the fortunesArray property is set.

I think the array is getting autoreleased and thats why the crash is appearing. Try allocating memory for the array
self.fortunesArray =[[NSMutableArray alloc] initWithObjects:text0,text1...text123,nil];
and release the array once you are done with it. But I will Strongly recommend using plist file as suggested by Christopher.

Related

Having trouble with this alloc/releasing issue

I've tried numerous different attempts at it but always ends in leaks or errors. So here is my code, with the allocating and releasing bits taken out. I'd like to know how people suggest i should go about doing this?
.h
#import "MatchingColors.h"
#interface MagicSchemeView : UIViewController {
NSMutableArray *colors;
}
.m
colors = [MatchingColors monochromaticWithH:h S:s B:b WithComplementary:NO];
Then in MatchingColors.m:
+(NSMutableArray *)monochromaticWithH:(float)h S:(float)s B:(float)b WithComplementary:(BOOL)complementary {
return result;
}
Like i say, my attempts at allocating and releasing here seem to be going wrong. Ideas?
This should work
A place for the [colors release]; would be after you're done with it. Which would be as soon as you know you don't need it, or would be done on dealloc. Make sure dealloc is a last resort to put this release.
.m:
colors = [[MatchingColors monochromaticWithH:h S:s B:b WithComplementary:NO] retain];
+(NSMutableArray *)monochromaticWithH:(float)h S:(float)s B:(float)b WithComplementary:(BOOL)complementary
{
NSMutableArray *result = [[[NSMutableArray alloc] init] autorelease];
// Create the result here
return result;
}

message sent to deallocated instance ! cant find error

alright I am looking for this error since 2 hours and I just cant figure it out please help me.
I have the following situation I have 2 viewcontroller.
one presents the other one as modalview like that.
SearchViewController *searchViewController = [[SearchViewController alloc]init];
[searchViewController setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
searchViewController.delegate = self;
searchViewController.senderTag = [sender tag];
[self presentModalViewController:searchViewController animated:YES];
[searchViewController release];
in my searchviewcontroller I do this in the .h file
BSKmlResult *selectedAirport;
#property (nonatomic, retain) BSKmlResult *selectedAirport;
in the .m file i synthesize it and then set it like that
selectedAirport = [self.airportList objectAtIndex:indexPath.row];
and then release it here
- (void)dealloc {
[selectedAirport release];
[super dealloc];
}
in the delegate methode of my SearchViewController which is implemented in the first
viewcontroller where I also present the SearchViewController
i have the following
if (controller.selectedAirport) {
if (departureAirport) {
[departureAirport release];
}
departureAirport = [controller.selectedAirport copy];
}
[self dismissModalViewControllerAnimated:YES];
I narrowed down where the error happens it is in the dealloc of my SearchViewController
[selectedAirport release];
but I cant figure out where my mistake is
please help
selectedAirport = [self.airportList objectAtIndex:indexPath.row];
You arent retaining selectedAirport here.
Change it to
self.selectedAirport = [self.airportList objectAtIndex:indexPath.row];
Since you couldnt find it out, probably you dont know this...
If you dont access member variables by self.memberVariable, you are not accessing its property. Thus, it was not getting retained.
Ofcourse you can also retain it by saying
selectedAirport = [[self.airportList objectAtIndex:indexPath.row] retain];
But whats the use of your property then...
You need to use self. to run it through the synthesized method, to get the retain.
self.selectedAirport = [self.airportList objectAtIndex:indexPath.row];
I know this post is quite old but just wanted to add something useful to it. In the above case the member variable name and property name are identical so you may still by mistake set the value of member variable instead accessing it using property that will call retain implicitly. Hence the best way to make sure you always use self.selectedAirport is to name the member variable something different than your property.
For example, in .h file you can have below implementation:
NSString *_selectedAirport;
then encapsulate it inside a property like below
#property(nonatomic,retain) NSString *selectedAirport;
and in .m implementation file synthesize it like below:
#synthesize selectedAirport = _selectedAirport;
By doing above, if you try to access it like below
selectedAirport = [self.airportList objectAtIndex:indexPath.row];
then it would result in an error and you will be prompted to use self.selectedAirport.
Also in this case your dealloc method can have either
self.selectedAirport = nil;
or
[_selectedAirport release];

Confused why one piece of code works and another doesn't in Objective C

Sorry about the title being extremely vague, I'm new to Objective C and struggling a little with it. Basically I have the following section of code:
Graph *graph1 = [[Graph alloc] init];
[graph1 addNode:#"TEST"];
which is working to a degree. But I want to change it because the above code happens on a button press, and therefore I assume I am creating a new "*graph1" every time I do this. I thought I could simply change it to this:
if(self = [super init])
{
[self setGraph: [[Graph alloc] init]];
}
return self;
Where the above is in the init method, and below is the modified function:
[graph addNode:#"TEST"];
However when debugging I've found addNode method is never called when it's like this.
Thanks
Zac
This is testViewController.h
#import <UIKit/UIKit.h>
#class Graph;
#class Node;
#interface testViewController : UIViewController {
Graph *graph;
UILabel *label;
}
#property (nonatomic, retain) IBOutlet UILabel *label;
#property (nonatomic, retain) Graph *graph;
- (IBAction) buttonPressed:(id)sender;
#end
This is textViewController.m
#import "testViewController.h"
#import "Graph.h"
#implementation testViewController
#synthesize label, graph;
- (id)init
{
if(self = [super init])
{
[self setGraph: [[Graph alloc] init]];
}
return self;
}
- (IBAction)buttonPressed:(id)sender
{
//Graph *graph1 = [[Graph alloc] init];
[graph addNode:#"TEST"];
Node *node1 = [[Node alloc] initWithLabel: #"LABEL"];
label.text = node1.label;
}
The first thing that comes to mind is that graph is nil and thus invoking a method (sending a message) to it will result in nothing. An unwanted release will cause an EXC_BAD_ACCESS, and this seems to be not the case.
I suppose you are calling all of this in a UIViewController subclass, right? Are you sure the right init is called? If you are using a NIB you should override the -(id)initWithNibName:bundle: and place you code there. I guess the code is probably in the plain -(id)init, since you are calling [super init] and not [super initWithNibName:nameOrNil bundle:bundleOrNil], but this way, if initialize the controller with the NIB you custom code is never called and thus graph is nil.
By the way, if the graph property is (retain) you are also causing a memory leak in the init.
I'm sure you're through this problem now, but I agree that the reason "add" is "not being called" is that your graph object is nil at that moment
I'd say, first put a test message around your "addNode" call
NSLog(#"We tried to add here");
[graph addNode:#"TEST"];
That will show you that the add is being called -- I bet it is.
Then, where you had your previous call to initialize "graph" right before your add call, try conditionally initializing it:
if(graph == nil) graph = [[Graph alloc] init];
[graph addNode:#"TEST"];
Note, this is all just to find the problem. Finally I'd say you have some challenges in here with how you are dealing with memory. You may not have reference issues, but later leaks. And depending upon how often this code is executed it could be an issue.
But at least you may get to your issue easier with the above tests.
Have you declared the graph variable in the header? ie: Graph *graph; and the corresponding #property (nonatomic, retain) Graph *graph;
Then I would do this:
-(id) init {
graph = [[Graph alloc] init];
[graph retain];
}
that might help (the only reason I think it wouldn't would be because a) if your variable wasn't declared then you would get a warning like graph may not respond to addNode and if it wasn't retained then your app would crash when it runs)... other than that, I can't see what would be the problem. If that doesn't work, can you please post all your code from your .h and .m files?
Then I would do this:
-(id) init {
graph = [[Graph alloc] init];
[graph retain];
}
that might help
This would result in a memory leak. The retain count of the object pointed to by graph will have a retain count of 2. Not ideal. If you declare the property with the retain attribute then
[self setGraph:[[[Graph alloc] init] autorelease]];
should do it. I go with -
self.graph = [[[Graph alloc] init] autorelease];
There could be many reasons the addNode: method is not being called. Put break points in the enclosing method and see if everything is working as you expect it to.

Problem with sharing variables between views - missing something?

I know im missing something but my friend and I can figure out what.
Firstly.. I have two .hs and .ms that I'd like to share data between - two view controllers
In the first .h i have this - that makes the variables and properties them
//top half of .h
//Passing to Submit Page
NSMutableString *messageString;
NSInteger theirTime;
}
#property (nonatomic, readwrite) NSInteger theirTime;
#property (nonatomic, retain, readwrite) NSMutableString *messageString;
/actions
#end
Then in the respective .m - sythesize them
#synthesize messageString, theirTime;
then from the new .h and .h i need to acces them.. so In view did load i do this
- (void)viewDidLoad {
messageString = [[NSMutableString alloc] init];
MemoryViewController *controller = [[MemoryViewController alloc] init];
timeInSeconds = controller.theirTime;
NSLog(#"Time = %d", timeInSeconds);
messageString = controller.messageString;
NSLog(#"Message - %#", messageString);
[controller release];
NSUserDefaults *HighScore = [NSUserDefaults standardUserDefaults];
bestTime.text= [NSString stringWithFormat:#"Best Time:%d", [HighScore integerForKey:#"integerKey"]];
currentTime.text = [NSString stringWithFormat:#"Current Time:%d", timeInSeconds];
[super viewDidLoad];
}
and at the top
#import "MemoryViewController.h"
and now the .h to show you all what the variables are
IBOutlet UILabel *bestTime;
IBOutlet UILabel *currentTime;
int timeInSeconds;
NSMutableString *messageString;
So. In short - I made variables made properties, and synthesized them, then in the view i make an instance of the other VC, then try use them to do things
Log out put
2010-04-15 20:53:09.105 Memory[3538:207] Time = 0
2010-04-15 20:53:09.107 Memory[3538:207] Message - (null)
Any ideas guys would be great... if you need more code/ less code just say.. ive tried other blogs but they all do it with app delegates.. and i dont like global variables.
Cheers
Sam
You initialised a new MemoryViewController instance in your -viewDidLoad, so of course all of its instance variables are 0 or nil. If you already have a MemoryViewController that you need to get the properties from, you need to reference that instance instead of creating a new one.

Why is this line of Objective-C leaking memory?

I'm writing an iPhone app. I have a header file that looks like this:
#interface EditTagsViewController : UITableViewController {
NSMutableArray *allTags;
NSMutableArray *selectedTags;
NSInteger currentFavorite;
}
#property (nonatomic, retain) NSMutableArray *allTags;
#property (nonatomic, retain) NSMutableArray *selectedTags;
#property (nonatomic) NSInteger currentFavorite;
#end
In the implementation file, my viewDidLoad method looks like this:
- (void)viewDidLoad {
NSMutableArray *aTags = [[NSMutableArray alloc] initWithArray:[Tag findAllTags]];
self.allTags = aTags;
[aTags release];
NSMutableArray *sTags = [[NSMutableArray alloc] initWithArray:[Tag findByFavoriteId:currentFavorite]];
self.selectedTags = sTags;
[sTags release];
UIBarButtonItem *add = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(addNewTag:)];
self.navigationItem.rightBarButtonItem = add;
[add release];
[super viewDidLoad];
}
Here is my dealloc method:
- (void)dealloc {
[allTags release];
[selectedTags release];
[super dealloc];
}
What's confusing to me is that when I run the app both in the simulator and on the device itself, using Instruments (memory leaks), it tells me that this line in my viewDidLoad method is leaking an array:
self.selectedTags = sTags;
It's confusing because I'm using the exact same technique with 2 different variables, and yet no leak is reported with the first one.
I feel like I'm missing something obvious here. Any ideas?
Your code looks correct to me. Is it possible that one of [Tag findAllTags] or [Tag findByFavoriteId:] is leaking? Are you making sure to set self.allTags and self.selectedTags to nil in dealloc?
Be mindful of the difference between saying self.allTags = ... and allTags = .... Because allTags is a property and has the retain attribute, whenever you assign via self.allTags = ..., it implicitly calls the setter method [self setAllTags:...], which invokes retain on the new value and release on the old value (if any). You're doing it correctly in this code sample, but if elsewhere you're assigning straight to allTags (without the self.), you're not releaseing the old value, which may be the source of the leak. Likewise for selectedTags.
Have a look at findByFavoriteId is there a retain there? That is the only difference I can see between the aTags and sTags are used in your example