I don't understand why if I write these code
icons = [[NSArray alloc] initWithObjects:
#"appointment",
#"work",
#"anniversary",
#"me",
nil];
the app crashed. But then I replaced by these code
icons = [NSArray alloc] arrayWithObjects:
#"appointment",
#"work",
#"anniversary",
#"me",
nil];
and the app did't crash.
But there is the same affect between these methods !
I don't know why ? Can u help me ?
initWithObjects method means you have to release the object of array whenever this is not required as this is instance method and for more details click:
arrayWithObjects method means you don't need to release the object of array whenever this is not required as this is class method and for more details click:
If you are not clear with the points so revert me..
Related
I'm only new to iPhone development, so my apologies if this is a silly question. I'm building various apps based on a book I'm reading and one of their suggestion was to build a mini web browser. I thought this would be easy, but while most of it is, I'm seriously struggling with the NSDictionary.
I have a UISegmentedControl used to display various bookmarks. The bookmark name that is displayed on the buttons of the UISegmentedControl is going to be my key and the url is the value associated with it.
I first try to declare an NSDictonary as a private (global variable), but since I could not get it to work, I resorted to declare it in my header file as follows:
#property (nonatomic, retain) NSDictionary *bookmarks;
I synthesize it and I initialized it in the viewDidLoad as follows:
- (void)viewDidLoad
{
bookmarks = [NSDictionary
dictionaryWithObjectsAndKeys:#"http://www.microsoft.com",
#"Microsoft",
#"http://www.google.com",
#"Google",
#"http://www.apple.com",
#"Apple",
#"http://msdn.microsoft.com",
#"MSDN", nil];
[super viewDidLoad];
}
I then associated a control with my segmented control and when the event is triggered and the function is called I've got the following code which is called:
- (IBAction) getShortcut:(id)sender
{
NSString *shortcut;
shortcut = [shortcuts titleForSegmentAtIndex:shortcuts.selectedSegmentIndex];
NSString *url = [bookmarks valueForKey:shortcut];
//[self navigateTo: url];
[url release];
}
When a button from the UISegmentedControl is clicked, I extract the value and stored it into shortcut and then I try to use the shortcut variable as a key to extract the associated value from the NSDictionary "bookmarks" but it keeps crashing on NSString *url = [bookmarks valueForKey:shortcut];
and bombs out of my function and displays the usual error EXC_BAD_ACCESS
Any help would be greatly appreciated.
T.
You have two options. one is to deal with the ivar directly as #Matt S. posted. Note that in this case you need to keep you object with enough retain count. You're using and auto released object and causing the error.
The other option is to use the property you already defined:
self.bookmarks = [[NSDictionary ...]];
And the property retains it.
That dictionary is autoreleased.
Try this:
self.bookmarks = [NSDictionary dictionaryWithObjectsAndKeys...]
You didn't retain the NSDictionary.
Do:
bookmarks = [[NSDictionary
dictionaryWithObjectsAndKeys:#"http://www.microsoft.com",
#"Microsoft", nil] retain];
The problem is, that you do not retain "bookmarks" in the viewDidLoad method. There is an naming convention mentioned somewhere in the Apple docs: If an intialisation method starts with "init..." the returned object is retained, if not you have to do it yourself. The "dictionaryWithObjectsAndKeys" returns and object with retain count 0, which means, that after the scope of assignment (your viewDidLoad method) it is immediatly released again.
So just put a
[bookmarks retain];
after your initalisation and you are done. Another solution which does the retaining for you
bookmarks = [[NSDictionary alloc] initWithObjectsAndKeys ...];
And you shouldn't release the url in your action. It gets released, once you release the dictionary
Tons of similar questions, but none of their answers seem to answer mine...
I'm creating my array as such:
imgArray = [NSMutableArray arrayWithCapacity:10];
Later (in another function) I am trying to add an object to it:
Attachment newAttachment = [[[Attachment alloc] init] autorelease];
newAttachment.fileName = filename;
newAttachment.file = file;
[imgArray addObject:newAttachment];
This results in the iPhone app freezing up. The simulator seems fine; the clock on the status bar keeps ticking, I don't get any error messages, but my app is no longer responding.
What am I doing wrong?
It seems you are not retaining imgArray. Are you? Try,
imgArray = [[NSMutableArray alloc] initWithCapacity:10]
if not.
just do
imgArray = [[NSMutableArray arrayWithCapacity:10] retain];
all class methods if return an object is returned with retain count 1 and object already in autorelease pool so if want to use that object beyond the current working block the you should always retain that object because then reference is lost outside the block.
Hey all, I have an array that holds all of the .aif file paths in my app, which I found by using mainBundle and resources.
This array needs to be passed down through 2 view controllers to reach where it is actually used. The problem is, it either crashes or logs something totally wrong. When I debug I get an EXC_BAD_ACCESS note at the crash, but not when I run it normally where it just crashes.
Here's the place where it works;
- (void)buildDrumTrigger {
defaultSounds = [[NSArray alloc] initWithObjects: #"kick_3", #"aif", #"snare_1", #"aif", #"HiHat_1", #"aif", #"ride_1", #"aif", #"crash_1", #"aif", #"crash_2", #"aif", #"crash_3", #"aif", #"wave_1", #"aif", nil];
self.DrumObject = [[DrumTrigger alloc] initWithSounds:defaultSounds:5:volumeBox];
[defaultSounds release];
NSLog(#"Possible Sounds: %#", DrumObject.possDrumSounds);
}
That returns a long list of paths that end in fileName.aif. You get the idea.
However...
// Change the current view to the options window.
- (IBAction)goToOptionsView {
NSLog(#"Loading options menu");
NSLog(#"DrumObject.drumSounds: %#", DrumObject.drumSounds);
NSLog(#"DrumObject.possDrumSounds: %#", DrumObject.possDrumSounds);
optionsViewController.soundBox2 = DrumObject.drumSounds;
optionsViewController.possDrumSounds = DrumObject.possDrumSounds;
[self presentModalViewController:optionsViewController animated:YES];
}
That snippet causes a crash. If I comment out the parts where it deals with possDrumSounds, it works fine. Otherwise it crashes or somehow changes the array to contain random objects like UIViewControllers that I have no idea where they came from.
All help appreciated, thanks!
You're probably keeping around array inside of DrumObject without retaining it, so it ends up getting overwritten with garbage.
You're releasing defaultSounds in buildDrumTrigger, so by the time other methods try to access it, it points to data that has been deallocated.
EXC_BAD_ACCESS indicates you're trying to access memory you can't access, normally because you've already released it.
This code is leaking, the performance tool blames two leaks on this block of code. If i comment it out the leak doesn't happen. Any help pinning it down would be greatly appreciated.
Leaks:
Malloc 48 bytes
NSCFarray 32 bytes
Code Block:
NSArray *myArray = [[NSArray alloc] initWithObjects: #"Add", #"Edit", nil];
segmentControl = [[UISegmentedControl alloc] initWithItems:myArray];
[myArray release];
[segmentControl setSegmentedControlStyle:UISegmentedControlStyleBar];
[segmentControl setMomentary:YES];
[segmentControl addTarget:self action:#selector(addOrEditPressed) forControlEvents:UIControlEventValueChanged];
UIBarButtonItem *myBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:segmentControl];
self.navigationItem.rightBarButtonItem = myBarButtonItem;
[myBarButtonItem release];
As long as segmentControl is nil when you enter the code block and is being released somewhere else in your code (like dealloc or viewDidUnload) then you are doing nothing wrong.
Have you tried running your code under the static analyzer (Xcode menu: Build | Build & Analyze)?
Instruments can sometimes generate false positives when searching for leaks. If the leaked memory doesn't accumulate over time, your worst case scenario is that your program is leaking a total of 80 bytes. Leaks that grow over time are what you should be concerned about.
Is segmentControl meant to be released?
myArray's retain count is still one after this section of code. When you add it to the initWithItems to create the segmentControl, it now has a reference to the object.
Is that possibly the leak?
Is segmentControl a property? Do you nil it in viewDidUnload?
No alloc is required when you create the array.
NSArray *myArray = [[NSArray alloc] initWithObjects: #"Add", #"Edit",
nil];
Use :
+ (id)arrayWithObjects:(id)firstObj, ...
Try it this way, this also doesn't needs release.
I'm doing an iPhone application which uses a navigation control to browse through some data. This data is stored in a sqlite database and I have a class which gets it and returns it in a NSMutableArray of NSStrings.
The problem is that in the first screen of the navigation everything works prefectly, but in the second screen (another view which is pushed) the same code fails because the NSMutableArray gets corrupted. In the debugger I can see that it is returned correctly, but when it's time to use it the pointers have become corrupted and the application crashes.
I have put breakpoints in all my functions, and I can't see anywhere where it can get corrupted. And as the first view, which uses the same exact code, even accesing the same eact tables, works correctly I don't really know where to look.
If anyone want to have a look at the code I have uploaded it to my site: http://sachafuentes.com/iBacus.zip
Thanks in advance.
UPDATE:
The problem lies in the function where I get the data, which looks like (this is a simplified version with some pseudo-code).
-(NSMutableArray *) getPaises {
NSMutableArray * paises;
paises = [[NSMutableArray alloc] init];
while( get new row ) {
NSString *aPais = get the value;
[paises addObject:aPais];
[aPais release];
}
return paises;
}
If I comment out [aPais release] everything works, but to me this looks like a memory leak, as the NSString won't be released.
Okay, here's the problem:
NSString *aPais = [NSString stringWithUTF8String:(char*)sqlite3_column_text(compiledStatement, 0)];
By convention, any time that you see an alloc and an init, you need a release somewhere down the road.
By convention, any time that you use an xWithX: style method, the resulting object will be released for you.
Therefore, this statement:
[aPais release];
will cause your method to crash, as the object is released before it should be. Just remove this line, set your NSMutableArray instance to be autorelease-d and you should get better results.
Look for wrong memory management, that's the likeliest cause for crashes. I think you release your objects somewhere where you shouldn't and therefore you have dangling pointers in the array.
Update1
[aPais release] is wrong, as you don't retain it anywhere in this method. Returned values should always be autoreleased. You should have the same amount of retain as release in your code.
(Some people argue that a retain can also be an alloc init, but I always try to use alloc init autorelease, but this is a matter of style.)
BTW
You should autorelease your array, you're only retaining it here with [[alloc] init].
Any object that you alloc and init must be release-d when you're finished with it, or you will have a memory leak.
Since you are passing the reference outside the scope of the getPaises method, you must autorelease the NSMutableArray, or you will have a memory leak:
paises = [[[NSMutableArray alloc] init] autorelease];
Can you please clarify the step here:
NSString *aPais = get the value;
It's not clear what happens in "get the value" and I suspect this is one cause of instability.
I see that the code is (verbatim)
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
NSString *aPais = [NSString stringWithUTF8String:
(char*)sqlite3_column_text(compiledStatement, 0)];
[paises addObject:aPais];
[aPais release];
}
...and it's exactly as #gs puts it. aPais is autoreleased and should not be released.
You can also use a convenience constructor to initialize the NSMutableArray:
NSMutableArray *paises = [NSMutableArray array];
This is equivalent to doing:
NSMutableArray *paises = [[[NSMutableArray alloc] init] autorelease];