Populating an NSArray/NSMutableArray, the right way - objective-c

This is a general question about memory management and best practices when using Cocoa arrays.
Which of the following is "better":
NSArray *pageControllers = [[NSArray alloc] initWithObjects:
[[Page1 alloc] initWithNibName:#"Page1" bundle:nil],
[[Page2 alloc] initWithNibName:#"Page2" bundle:nil],
[[Page3 alloc] initWithNibName:#"Page3" bundle:nil],
nil];
...then release NSArray later when not needed anymore...
Or
NSMutableArray *pageControllers = [[NSMutableArray alloc] init];
UIViewController *page1 = [[Page1 alloc] initWithNibName:#"Page1" bundle:nil];
[pageControllers addObject:page1];
[page1 release];
UIViewController *page2 = [[Page2 alloc] initWithNibName:#"Page2" bundle:nil];
[pageControllers addObject:page2];
[page2 release];
UIViewController *page3 = [[Page3 alloc] initWithNibName:#"Page3" bundle:nil];
[pageControllers addObject:page3];
[page3 release];
...then release NSMutableArray later when not needed anymore...
Or is there something else that's even better?

Either way works fine, but keep in mind that you'll be leaking all your page objects in the first example.

Related

EXC_BAD_ACCESS when I work with arrays

I always have error when working with arrays (non ARC code).
My code:
#implementation InfoController
NSMutableArray *lbCityArray;
NSMutableArray *lbTimeArray;
NSMutableArray *lbCameInArray;
NSMutableArray *lbCameOutArray;
NSMutableArray *lbInArray;
NSMutableArray *lbOutArray;
in ViewDidLoad I do something
- (void)viewDidLoad
{
[super viewDidLoad];
lbCityArray = [[NSMutableArray alloc] initWithCapacity:1];
lbTimeArray = [[NSMutableArray alloc] initWithCapacity:1];
lbCameInArray = [[NSMutableArray alloc] initWithCapacity:1];
lbCameOutArray = [[NSMutableArray alloc] initWithCapacity:1];
lbInArray = [[NSMutableArray alloc] initWithCapacity:1];
lbOutArray = [[NSMutableArray alloc] initWithCapacity:1];
//—add some values to arrays
NSString *City = #"London";
[lbCityArray addObject:City];
//—————————————-----------------------//
}
and always when I click Back button app crash with EXC_BAD_ACCESS. If I comment adding values to array all work, Back button don't crash app. I read if you use non ARC code you must manually release in dealloc.
I add to dealloc
[_InfoTableView release];
[lbCityArray release];
[lbTimeArray release];
[lbCameInArray release];
[lbCameOutArray release];
[lbInArray release];
[lbOutArray release];
[super dealloc];
and nothing changes, app still crash. Where can be problem ?
Solution - I move to ARC and all problems gone. Thanks.
It would help a lot if you made your variables into instance variables instead of global variables.
Change this:
#implementation InfoController
NSMutableArray *lbCityArray;
NSMutableArray *lbTimeArray;
NSMutableArray *lbCameInArray;
NSMutableArray *lbCameOutArray;
NSMutableArray *lbInArray;
NSMutableArray *lbOutArray;
into:
#implementation InfoController {
NSMutableArray *lbCityArray;
NSMutableArray *lbTimeArray;
NSMutableArray *lbCameInArray;
NSMutableArray *lbCameOutArray;
NSMutableArray *lbInArray;
NSMutableArray *lbOutArray;
}
Without the curly braces you are actually creating global variables, not instance variables.

UI issues in UITabBarController

here is the source code
problem: TabbarController is not working properly...
please help me
NSArray *actionButtonItems = #[searchItem, refreshItem];
self.navigationItem.rightBarButtonItems = actionButtonItems;
NSMutableArray *items = [[NSMutableArray alloc] init];
[items addObject:[[UITabBarItem alloc]
initWithTabBarSystemItem:UITabBarSystemItemHistory tag:1]];
[items addObject:[[UITabBarItem
alloc]initWithTabBarSystemItem:UITabBarSystemItemContacts tag:2]];
tabBar.items = items;
tabBar.delegate = self;
addFriends = [[AddFriendsViewController alloc] initWithNibName:#"AddFriendsViewController" bundle:nil];
[self.tabView addSubview:addFriends.view];
//[self.tabsetSelectedIndex = 0];
_tabBarController.selectedIndex = 0;
[self.view addSubview:_tabBarController.view];
Before you call
[self.tabView addSubview:addFriends.view];
you should call
[self.tabView setViewControllers:[NSArray arrayWithObjects: addFriends, nil]];
Set selectedViewController property of UITabBarController:
self.myTabBarController.selectedViewController = myViewController;
Use as below
self.myTabBarController.selectedViewController
= [self.myTabBarController.viewControllers objectAtIndex:0];

I want grab 1 random item out of 4 different arrays and display the result

I have an app that uses 3 arrays. The interface is basically 3 picker wheels that one can use to select from a plethora of choices to form a 3 part answer.
But, I need to randomize these not unlike what urban spoon does short of the graphical aspect.
I just need to implement a button that will reach into the arrays and give me a random selection from each array.
Here is a snippet of my code as it sits now...
Any help would be appreciated...
import "DoubleComponentPickerViewController.h"
#implementation DoubleComponentPickerViewController
#synthesize doublePicker;
#synthesize firstTypes;
#synthesize middleTypes;
#synthesize lastTypes;
-(IBAction)buttonPressed
{
NSInteger firstRow = [doublePicker selectedRowInComponent:kfirstComponent];
NSInteger middleRow = [doublePicker selectedRowInComponent:kmiddleComponent];
NSInteger lastRow = [doublePicker selectedRowInComponent:klastComponent];
NSString *first = [firstTypes objectAtIndex:firstRow];
NSString *middle = [middleTypes objectAtIndex:middleRow];
NSString *last = [lastTypes objectAtIndex:lastRow];
NSString *message = [[NSString alloc] initWithFormat:#"%# %# %# test.",first, middle, last];
UIAlertView *alert = [[ UIAlertView alloc] initWithTitle:#"Description:"
message:message
delegate:nil
cancelButtonTitle:#"Cancel"
otherButtonTitles:nil];
[alert show];
[alert release];
[message release];
}
- (void)viewDidLoad
{
NSArray *firstArray = [[NSArray alloc] initWithObjects:
#"a",#"b",#"c",#"d",nil];
self.firstTypes = firstArray;
[firstArray release];
NSArray *middleArray = [[NSArray alloc] initWithObjects:
#"A",#"B",#"C",#"D",nil];
self.middleTypes = middleArray;
[middleArray release];
NSArray *lastArray = [[NSArray alloc] initWithObjects:
#"1",#"2",#"3",#"4",nil];
self.lastTypes = lastArray;
[lastArray release];
You can pick a random element of firstTypes like this:
NSObject *randomFirst = [self.firstTypes objectAtIndex:arc4random_uniform(self.firstTypes.count)];

NSMutableArray addObject in for loop - memory leak

i'm putting strings (which are filenames of files in a certain directory) into an NSMutableArray with a for loop:
h-file:
#import <Three20/Three20.h>
#interface AlbumController : TTThumbsViewController {
NSMutableArray *images;
}
#property (nonatomic, retain) NSMutableArray *images;
#end
m-file:
#import "AlbumController.h"
#import "PhotoSource.h"
#import "Photo.h"
#implementation AlbumController
#synthesize images;
-(void)createPhotos {
NSString *bundleRoot = [[NSBundle mainBundle] bundlePath];
NSArray *dirContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:bundleRoot error:nil];
NSArray *onlyJPGs = [dirContents filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"self ENDSWITH '.jpg'"]];
NSMutableArray *pics = [[onlyJPGs copy] autorelease];
if(!self.images) {
self.images = [[NSMutableArray alloc] init];
}
for(int i = 0; i < [onlyJPGs count]; i++)
{
//NSLog([pics objectAtIndex:i]);
NSString *ImgURL = [#"bundle://" stringByAppendingString:[pics objectAtIndex:i]];
Photo *photo = [[Photo alloc] initWithURL:ImgURL smallURL:ImgURL size:CGSizeMake(320, 212)];
[images addObject:photo];
[photo release];
}
}
-(void)viewDidLoad{
[self createPhotos]; // method to set up the photos array
self.photoSource = [[PhotoSource alloc]
initWithType:PhotoSourceNormal
title:#"Chili Pflanzen"
photos:images
photos2:nil
];
}
#end
i do not have any problem in the simulator but on my iPod...
Error message:
Data FOrmatters temporarily unavailable, will re-try after a 'continue'. (Unknown error loading shared library "/Developer/usr/lib/libXcodeDebuggerSupport.dylib")
thanks in advance
I think you should use mutableCopy and not copy on your pics array.
so instead of:
NSMutableArray *pics = [[onlyJPGs copy] autorelease];
you should use:
NSMutableArray *pics = [[onlyJPGs mutableCopy] autorelease];
More information about copy/mutablecopy in this question: Copy & mutableCopy?
Looks like the main issue is with
[images addObject:[[Photo alloc] initWithURL:ImgURL smallURL:ImgURL size:CGSizeMake(320, 212)]];
Here you are alloc'ing Photo but not releasing it. When you add an object to an array it increases the retain count for it.
Try changing it to
Photo *photo = [[Photo alloc] initWithURL:ImgURL smallURL:ImgURL size:CGSizeMake(320, 212)];
[images addObject:photo];
[photo release];
In addition ...
I'd change
self.images = [[[NSMutableArray alloc] init] autorelease];
to
if(!self.images) {
self.images = [[NSMutableArray alloc] init];
}
Otherwise there is the potential for a memory leak if it has already been initialized, as well as that you probably do not want it autoreleased;
Your NSMutableArray instance is autoreleased. You are assigning it to the images ivar. The fact that you have declared it as a retained property doesn't matter, because you aren't assigning it to the property. My guess is that you meant to assign to the property, and the crash is caused by the inadvertent deallocation.
Change:
images = [[[NSMutableArray alloc] init] autorelease];
...to:
self.images = [[[NSMutableArray alloc] init] autorelease];
...or:
images = [[NSMutableArray alloc] init];
Also note that your property is declared as NSArray when you are allocating an instance of NSMutableArray.
Also see the Memory Management Programming Guide.

Get & Edit NSMutableArray from different class file

I am trying to access and change a array from a different class file. When using a NSLog, I get a result of (null). Below is my code:
RootViewController.h
NSMutableArray *listOfItems;
#property (nonatomic, retain) NSMutableArray *listOfItems;
RootViewController.m
#synthesize listOfItems;
listOfItems = [[NSMutableArray alloc] init];
[listOfItems addObject:#"One"];
[listOfItems addObject:#"Two"];
[listOfItems addObject:#"Three"];
SecondViewController.m
RootViewController *test = [[RootViewController alloc] init];
NSLog(#"Results: %#", test.listOfItems);
I get the following results in my console: Results: (null)
Thanks in advance,
Coulton
P.S. Obviously I have left out a bunch of code. I just tried to make it easier to read. If you need to see anything else, I would be more than happy to post more. Just ask
EDIT #1:
I am getting hundreds of NSLog Messages that look something like this:
*** __NSAutoreleaseNoPool(): Object 0x4e39020 of class __NSArrayI autoreleased with no pool in place - just leaking
And here's my init code:
- (id) init {
//NSLog(#"%#", theUserID);
// Set up database connection
NSString *myDB = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"database.db"];
database = [[Sqlite alloc] init];
[database open:myDB];
//Initialize the array.
listOfItems = [[NSMutableArray alloc] init];
// Add to array to display in the tableView
NSArray *listOfItemsTwo = [database executeQuery:#"SELECT * FROM albums"];
for (NSDictionary *rowone in listOfItemsTwo) {
NSString *getName = [rowone valueForKey:#"name"];
if (getName != NULL) {
[listOfItems addObject:getName];
[getName release];
}
}
return self;
}
I guess you reversed RootViewController.m and RootViewController.h snippets right?
Are you sure that the
listOfItems = [[NSMutableArray alloc] init];
gets called? Maybe you can put a breakpoint there.
EDIT: Order of RootViewController.m and RootViewController.h has been fixed in the question. It's not clear from the question where the above line is in the code. That's a important piece of information.
EDIT2: Example of init method.
#implementation RootViewController
- (id) init
{
listOfItems = [[NSMutableArray alloc] init];
[listOfItems addObject:#"One"];
return self;
}
#end