How can i lazily initialize a NSMutableArray of Buttons ? I do something like this :
-(NSMutableArray *)roasteryButtons
{
if(!roasteryButtons)
{
roasteryButtons = [ NSMutableArray new];
//other code
}
return roasteryButtons;
}
And don't know what to do to call this lazy initializer ? i.e. I need to initialize the array so that i may set the frame for every button in the array
What u have done is correct. Instead of allocating the array in the init method of class, u are allocating the array only when required. Thus it serves the purpose of lazily allocating.
In the class, Wherever you want the array, you just call,
NSMutableArray *arr = [self roasteryButtons];
Also declare the method in header file as, -(NSMutableArray*)roasteryButtons;.
If you want the reference of the array in other classes, the call like,
[classObj roasteryButtons];
I have shown it as instance method. You can also declare that as class method, if you want like that.
And release that in -(void)dealloc method.
I guess you know when to call this method, right ?
The first thing is that you shouldn't use "new" method, but [[NSMutableArray alloc] init] instead : You should have a look at all existing [Init] methods available for NSArray : there are a bunch of them (with capacity, with objects, etc...)
Anyway, you should add some parameters to your method [roasteryButtons] : parameters that will help the method to know, for instance how many buttons to create, what is the frame where they have to show, etc. So this will look a bit like
-(NSMutableArray *)roasteryButtonsWithFrame:(*Frame) andNumbersOfButtons:(int)
for example...
or instead of parameters, you can pass a reference to a delegate that will be able to give answers to those questions (How many buttons, what's my frame and bounds, etc.) So in this case, the method will look like :
-(NSMutableArray *)roasteryButtonsWithDelegate:(id)
(This delegate should implement a protocol that you will create, containing the different methods that the delegate will have to respond to. ie methods like [howManyButtons]...)
The Perfect Way to Lazy initialize is as follow
in .h file declare your NSMUtableArray as property as follow
#property (nonatomic,strong) NSMutableArray *array;
Now in .m file synthesize it and do lazy initialize in getter like as follow:
#synthesize array=_array;
(NSMutableArray *) array
{
(!_array) _array=[[NSMutableArray alloc]init];
//this line is called lazy intialization..this line will create MutableArray at program //run time.
return _array
}
Now answer why we need this is that it take care about that if no NSMutableArray is created then it create it at programme run time and like this your app will not crash.
You could make your method a class method:
+(NSMutableArray *)roasteryButtons {
in this way you will be able to call it like this:
[MyRoasteryButtonClass roasteryButtons];
and this will return you your object.
Hope this helps.
Related
From documentation, the MKMapView property, Annotations, is a NSArray and not a NSMutableArray. So Annotations is supposed to be "immutable". But MKMapView's instant methods : addAnnotation and removeAnnotation are capable of changing the Annotations array. So on the surface there seems to be some inconsistencies. There must be something I have missed. Hope that somebody knowledgable could shed some light on this.
By declaring the annotations property an NSArray, code that accesses the array through that property cannot safely modify it and must treat it as an immutable NSArray. However, that doesn't mean that the array itself is immutable.
Here's an example of how something like this might work:
#interface MyObject
{
// instance variables
NSMutableArray* internalArrayRepresentation;
}
// properties
#property (nonatomic, readonly) NSArray* immutableAccessor;
// methods
-(void)addItem:(NSObject*)object;
#end
#implementation MyObject
#synthesize immutableAccessor=internalArrayRepresentation;
-(id)init
{
if ((self = [super init]))
{
// create the mutable array
internalArrayRepresentation = [[NSMutableArray alloc] init]
}
}
-(void)addItem:(NSObject*)object
{
[internalArrayRepresentation addObject:object];
}
...
#end
In this example, you can see that internalArrayRepresentation is a mutable array, and that its accessible outside of MyObject as immutableAccessor. But because the property definition says that immutableAccessor is an NSArray, callers need to treat it that way and can't manipulate it.
There are other implementations that can accomplish this as well.
The typical reason to use a pattern like this is because you want MyObject to maintain control over the contents of the array: maybe only certain objects can be added, maybe objects need to be modified or cloned on the way in, maybe anything can be added but nothing can be removed, etc.
You're meant to use addAnnotation and removeAnnotation to add/remove annotations instead of manipulating the annotations array directly.
I assume both those functions do some processing as well as adding/removing annotations from the array.
General noob questions:
(1) How can I create an NSMutable array in a buttonClicked action that I can add more entries to during subsequent clicks of the same button? I always seem to start over with a new array at every click (the array prints with only 1 entry which is the most recent button's tag in an NSLog statement).
I have about 100 buttons (one for each character in my string called "list") generated by a for-loop earlier in my code, and each has been assigned a tag. They are in a scrollview within the view of my ViewController.
I wish to keep track of how many (and which ones) of the buttons have been clicked with the option of removing those entries if they are clicked a second time.
This is what I have so far:
-(void) buttonClicked:(UIButton *)sender
NSMutableArray * theseButtonsHaveBeenClicked = [[NSMutableArray alloc] initWithCapacity: list.length];
NSNumber *sendNum = [NSNumber numberWithInt:sender.tag];
[theseButtonsHaveBeenClicked addObject:sendNum at index:sender.tag];
NSLog(#"%#",theseButtonsHaveBeenClicked);
}
(2) I have read that I may be able to use a plist dictionary but I don't really understand how I would accomplish that in code since I cant type out the items in the dictionary manually (since I don't know which buttons the user will click). Would this be easier if I somehow loaded and replaced the dictionary in a plist file? And how would I do that?
(3) I also have no idea how I should memory manage this since I need to keep updating the array. autorelease?
Thanks for any help you can provide!
Okay, firstly you are creating a locally scoped array that is being re-initialised on every call to buttonClicked:. The variable should be part of the class init cycle.
You will also be better off with an NSMutableDictionary instead of an NSMutableArray. With a dictionary we don't have to specify capacity and we can use the button's tags as dictionary keys.
Here's what you need to do, these three steps always go together: property/synthesize/release. A good one to remember.
//Add property declaration to .h file
#property (nonatomic, retain) NSMutableDictionary * theseButtonsHaveBeenClicked;
//Add the synthesize directive to the top of .m file
#synthesize theseButtonsHaveBeenClicked;
// Add release call to the dealloc method at the bottom of .m file
- (void) dealloc {
self.theseButtonsHaveBeenClicked = nil; // syntactically equiv to [theseButtonsHaveBeenClicked release] but also nulls the pointer
[super dealloc];
}
Next we create a storage object when the class instance is initialised. Add this to your class's init or viewDidLoad method.
self.theseButtonsHaveBeenClicked = [[NSMutableDictionary alloc] dictionary]; // convenience method for creating a dictionary
And your updated buttonClicked: method should look more like this.
-(void) buttonClicked:(UIButton *)sender {
NSNumber *senderTagAsNum = [NSNumber numberWithInt:sender.tag];
NSString *senderTagAsString = [[NSString alloc] initWithFormat:#"%#",senderTagAsNum];
// this block adds to dict on first click, removes if already in dict
if(![self.theseButtonsHaveBeenClicked objectForKey:senderTagAsString]) {
[self.theseButtonsHaveBeenClicked setValue:senderTagAsNum forKey:senderTagAsString];
} else {
[self.theseButtonsHaveBeenClicked removeObjectForKey:senderTagAsString]; }
[senderTagAsString release];
NSLog(#"%#", self.theseButtonsHaveBeenClicked);
}
I do some iOS programming stuff and I have a UIViewController with a NSMutableArray:
#property (nonatomic, retain) NSMutableArray* mutableTestArray;
...
#synthesize mutableTestArray;
In viewDidLoad I want to call a method which is inside the implementation of this UIViewController:
//- (void)aTestMethod:(NSMutableArray *)myMutableTestArray;
[self aTestMethod:self.mutableTestArray];
So I call the method with a NSMutableArray which is an instance variable of the UIViewController. Inside this method, I do this:
myMutableTestArray = [NSMutableArray arrayWithCapacity:100];
//... looping & generating some objects and adding them to the array:
[myMutableTestArray adObject:myObject];
Now, I debug it and inside the method myMutableTestArray is fine. There are all objects inside the array. But leaving this method the instance variable mutableTestArray is empty.
So, where is the problem? Anyone an idea?
Note: I know I can access the instance variable with self.mutableTestArray and then everything will be okay, instead using it as a parameter, but I want to know what's wrong with my code.
Thank you in advance & Best Regards.
Parameters are passed by value in Objective-C. Thus, you are creating a copy of a pointer to the object and passing that into the method. When you do myParam = ... new object ...; that resets the copy to point to a new location, but has no effect on the original copy in the caller.
(To reiterate -- you are copying the pointer, not copying the object.)
To solve, declare your test method as returning an object:
- (NSMutableArray *)aTestMethod;
Then, you can simply:
self.mutableTestArray = [whateverObject aTestMethod];
(Since you aren't actually using the value passed in in the first place, there is no need for a parameter at all).
By your command
myMutableTestArray = [NSMutableArray arrayWithCapacity:100];
you are creating new allocation of mutableTestArray. So passing mutableTestArray as parameter to aTestMethod:
[self aTestMethod:self.mutableTestArray];
is useless because you override its value immediately when create this array inside your aTestMethod.
Try to create your array before passing it to your method (where you will fill it with data).
Remember that parameters are transmitted by value, so in aTestMethod: you are modifying not the original pointer but a copy of it!
For this to work, you should pass the address of the pointer as in
self aTestMethod:&(self.mutableArray)
then the prototype of the method should be
-(void)aTestMethod:(NSMutableArray **)myArray
and in the code of it you should used *myArray as in
*myArray = [[NSMutableArray alloc] init];
Yours, JB
I just did a search for my particular question and although the answers are close, I can't get my head around the answer...so I need some assistance.
I'd like to populate an array (NSMutableArray I suppose) with a group of dictionary objects that are parsed from JSON strings...the dictionary part I got, the JSON parsing I got, but when I try to put these objects into the NSMutableArray and NSLog it I get (null)... here are my steps (in a general way)
edit 1:
-The array I am creating is called NewFinalArray. it is an NSMutableArray, declared at the .h file and synthesized (and now alloc'd and init'd) as noted in the viewDidLoad method of the DetailViewController. It's contents are to be displayed in a UITableView.
-In DetailViewController, I have been successful in creating a plain NSArray/NSMutableArray and populating it with values that display in my UITableView.
-In the new scenario, I am receiving the information to be displayed through JSON strings which are retrievable through dictionary objects. I am using the Stig JSON libraries for iPHone/iPad. I have no problems there.
-All I wanted to do is getting the existing dictionary objects (which I can loop through from the existing array and see) and add them to a new Array to be used for displaying menu items in my UITableview.
I declared my mutableArray in my .h file
#interface blah : ...,...,...{
NSMutableArray *newFinalArray;
// other vars and IBOutlets
}
#property (nonatomic, retain) NSMutableArray *newFinalArray;
// other #property and (IBAction) stuff
#end
I then synthesize it in my .m file... I even alloc/inited it at viewDidLoad (it's a DetailViewController)
#synthesize this,that, newFinalArray; // keep track of newFinalArray, that's the one I want
- (void)viewDidLoad {
// other code
[[newFinalArray alloc] init]; // ya returns a warning, about not responding to alloc, but whatever (for now)
// I also tested of course without having to do that.
in my method that uses newFinalArray, the method is a recursive function that calls itself. each time it calls, it should add the dictionary object to the array (or does it?)
-(void)digTree:(NSArray *)array{
for (NSDictionary *dictionary in array){
// looping through the array
[self newFinalArray addObject:[dictionary]];
// more other code, and somewhere along the way I recurse
[self digTree:anotherArray];
}
}
when I try to NSLog (#"my final array is %#", newFinalArray) I get (null).
I am probably missing something here. I tried to add "nil" at the end. I am a little new/green to this , so if someone can lend a hand and let me know how to populate my newFinalArray with these dictionary objects it would be most appreciated.
[[newFinalArray alloc] init];
should be:
newFinalArray = [[NSMutableArray alloc] init];
This line is wrong too:
[self newFinalArray addObject:[dictionary]];
it should be:
[newFinalArray addObject:dictionary];
The first thing I notice that is wrong, is it should be:
newFinalArray = [[NSMutableArray alloc] init];
in viewDidLoad. See if that fixes it. It looks like there are other things wrong as well, so turn on warnings and see what else the compiler warns you about for hints.
How are the dictionaries stored? An alternative/probably easier way to do this would probably be to use arrayWithObjects:. Also, when using addObject:, there is no need to add nil (in fact, you can't add nil).
Alright, so I think I'm doing this the right way. I'm new to objective-C, so I'm not sure about the syntax... I have a set of code that I need to call multiple times, from different files. So I made a new class that has a method in it that I'll call and pass it the values that it needs.
Because I am passing different values I've put them in a dictionary and decided to just pass the dictionary. Here is that code:
NSNumber *testNum = [NSNumber numberWithInt:varMoney];
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
[dictionary setObject:#"OMG, Object 1!!!!" forKey:#"1"];
[dictionary setObject:#"Number two!" forKey:#"2"];
[dictionary setObject:testNum forKey:#"3"];
This code creates a test variable, and then puts it into the dictionary "dictionary." That all works, I have my nice little dictionary. However, now I need to create the class and it's method that will recieve the dictionary, and do something with it.
This is my class header file:
#import <UIKit/UIKit.h>
#interface EndOfTurnObjC : UIView {
}
#end
And this is the implementation file:
#import "EndOfTurnObjC.h"
#implementation EndOfTurnObjC
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// Initialization code
}
return self;
}
- (void)dealloc {
[super dealloc];
}
#end
I haven't created any of the real code, because I'm not sure how to do the passing. I need to create a function (Method?) in the class that will take a Dictionary has a parameter, and then return the dictionary.
I also have no idea how to call such a function because it's in the class. So, the questions are:
1: How do I define the method in the class to accept the dictionary as a parameter (and then perhaps some example code to pull out one of the objects in a dictionary, so I can be sure it works)
2: How do I return the dictionary at the end of the method?
3: How do I call this method, in the class, from another class? (I know it involves making an object of thing class and calling the method of the object... I think, but I'm not sure about the syntax.)
Please include relavent code for the 3 files (header, implementation, and the other class that I call from). Thank you so much, I've been working on this particular problem for a while now.
Apple's The Objective-C Programming Language is a good and pretty concise reference for Objective-C syntax. What you want is just a normal method that takes an NSDictionary as a parameter. So as given in that document:
A message with a single argument affixes a colon (:) to the selector name and puts the argument right after the colon. This construct is called a keyword; a keyword ends with a colon, and an argument follows the colon, as shown in this example:
[myRectangle setWidth:20.0];
So a method call to pass dictionary would look like:
[someObject setAttributes:dictionary];
In the header:
-(NSMutableDictionary *) doSomethingWithDictionary:(NSMutableDictionary *) aDict;
in the implementation:
-(NSMutableDictionary *) doSomethingWithDictionary:(NSMutableDictionary *) aDict{
//do something with the dictionary
return aDict;
}
To call the method:
NSMutableDictionary *returnDict=[EndOfTurnObjC doSomethingWithDictionary:dictionary];
Note that as a matter of good design you wouldn't want to pass a mutable dictionary around like a token. That is asking for trouble. Instead pass static dictionaries and get another dictionary back.
You also shouldn't be passing data to a UIView. Instead, your UIViewController should process the data and then populate the view's UI elements as needed.
if you just want to do stuff to your dictionary u just
-(void) changeMyDictionary:(NSMutableDictionary * ) dictionary_
{
[dictionary_ doStuff];
....
...
}
no need to return the dictionary.