Custom setter in objective c - iphone

I'm trying to declare a custom getter of a NSDictionary but I can't get it to work.
So far I have the #property declared and the synthesize syntax.
#property (nonatomic, strong) NSDictionary *variableDictionary;
#synthesize variableDictionary = _variableDictionary;
I want to declare a setter for the dictionary that gives it some standard values.
-(void)setVariableDictionary:(NSDictionary *)variableDictionary {
NSNumber *x = [NSNumber numberWithDouble:20];
NSNumber *a = [NSNumber numberWithDouble:10];
NSNumber *b = [NSNumber numberWithDouble:5];
NSDictionary *_variableDictionary = [[NSDictionary alloc] initWithObjectsAndKeys:a, #"a", b, #"b", x, #"x", nil];
}
When I use the above method I get a warning unused variable, and if I remove the underscore from the NSDictionary variable definition, I get an error saying 'redefinition of variable dictionary'.
I'm not sure of the correct way to do this.

_variableDictionary is already declared.
Replace
NSDictionary *_variableDictionary = [[NSDictionary alloc]
initWithObjectsAndKeys:a, #"a", b, #"b", x, #"x", nil];
with
_variableDictionary = [[NSDictionary alloc] initWithObjectsAndKeys:a, #"a", b, #"b", x, #"x", nil];

In your custom setVarableDictionary: setter method, when you write:
NSDictionary *_variableDictionary = _variableDictionary = [[NSDictionary alloc] initWithObjectsAndKeys:a, #"a", b, #"b", x, #"x", nil];
this declares and sets value for a new local variable within the scope of your function only. The warning message you get is because that variable is not used before it goes out of scope.
Instead of creating a local variable, you should just set the value of the ivar that underlies your property, like this:
_variableDictionary = [NSDictionary dictionaryWithObjectsAndKeys:a, #"a", b, #"b", x, #"x", nil];

First off, the setter implementation doesn't really make any sense considering it will never change the value (it's only function is to initialize). Nonetheless (assuming this would change), if you want to test the value in your setter, you could make it look something like this
-(void)setVariableDictionary:(NSDictionary *)variableDictionary {
NSNumber *x = [NSNumber numberWithDouble:20];
NSNumber *a = [NSNumber numberWithDouble:10];
NSNumber *b = [NSNumber numberWithDouble:5];
_variableDictionary = [[NSDictionary alloc] initWithObjectsAndKeys:a, #"a", b, #"b", x, #"x", nil];
NSLog(#"%#", _variableDictionary);
}
This will tell you whether or not the method is even being called. If it's not then you won't get the NSLog message.
This works on my end, if it's not on yours then there is something else going on.

If I understood your question. This might help
-(void)setVariableDictionary:(NSDictionary *)newVariableDictionary
{
if (variableDictionary != newVariableDictionary) {
variableDictionary = newVariableDictionary;
}
}
in your code.
-(void)setVariableDictionary:(NSDictionary *)variableDictionary {
its normal that it will give you an error when you redeclare your parameter. (NSDictionary *)variableDictionary

Try doing it this way, set your property as mentioned below:
#property (nonatomic, strong,setter = setTheVariableDictionary:) NSDictionary *variableDictionary;
Remove
-(void)setVariableDictionary:(NSDictionary *)variableDictionary
and write is as
-(void)setVariableDictionary:(NSDictionary *)thevariableDictionary
Hope this helps you.

Related

NSMutableArray release causes crash

I am using XCode for developing an iPhone app. I am new to this platform and need some help with a particular issue...
I have a method that processes some data and returns two integer values as NSNumber wrapped into a NSMutableArray.
Here is the method:
-(NSMutableArray *)processPoints:(int) x:(int) y
{
NSMutableArray *mutArray = [[NSMutableArray alloc] initWithCapacity:3];
int x9,y9;
// ...do some processing...
NSNumber* xNum = [NSNumber numberWithInt:x9];
NSNumber* yNum = [NSNumber numberWithInt:y9];
[mutArray addObject:xNum];
[mutArray addObject:yNum];
return [mutArray autorelease];
}
I call the above method from another method, where I copy the NSNumber stuff into local variables and then release the local copy of NSMutable array.
But the app crashes when releasing this NSMutable array (variable 'mutArray').
Here is the method:
-(void)doNinjaAction
{
NSMutableArray* mutArray = [self processPoints: x :y];
NSNumber* s1 = [[mutArray objectAtIndex:0] retain];
NSNumber* s2 = [[mutArray objectAtIndex:1] retain];
x = [s1 integerValue];
y = [s2 integerValue];
//...proceed with other stuff...
[mutArray autorelease]; //this is where the system crashes. same for 'release'
//instead of 'autorelease'
}
Can you please explain where I am going wrong with the process of memory release.
My understanding of the process is a bit shaky. Please help.
Because you're overreleasing the array. You alloc-init it in processPoints:, then you autorelease it - that's correct, this is how you dispose of its ownership.
After that, you don't need to and must not autorelease or release it once again. This is not malloc() from the standard library.
when you call the statement
NSMutableArray* mutArray = [self processPoints: x :y];
This itself acts as autorelease.
Hence releasing the array explicitly will cause the app to crash.
You are releasing mutArray more then once. Once in processPoints function and again in doNinjaAction.
To resolve the crash remove :
[mutArray autorelease];
-(NSMutableArray *)processPoints:(int) x:(int) y
{
NSMutableArray *mutArray = [[NSMutableArray alloc] initWithCapacity:3];
int x9,y9;
// ...do some processing...
NSNumber* xNum = [NSNumber numberWithInt:x9];
NSNumber* yNum = [NSNumber numberWithInt:y9];
[mutArray addObject:xNum];
[mutArray addObject:yNum];
[mutArray autorelase];
return mutArray;
}
try this one it'll resolve it.
-(NSMutableArray *)processPoints:(int) x:(int) y
{
NSMutableArray *mutArray =[[[NSMutableArray alloc] initWithCapacity:3]autorelease];
int x9,y9;
// ...do some processing...
NSNumber* xNum = [NSNumber numberWithInt:x9];
NSNumber* yNum = [NSNumber numberWithInt:y9];
[mutArray addObject:xNum];
[mutArray addObject:yNum];
return mutArray;
}
As #H2CO3 and #AppleDelegate suggested, it is right.
Still I would suggest to use ARC and convert your project to ARC enabled.
Go to Edit->Refactor->Convert to Objectiv-C ARC
Then you dont need to do any releases anywhere. It will take care itself of all the releases :)

Can I init an NSArray in a Singleton with specific values (like a const)?

I have a Singleton and I'd like to declare an NSArray, but I'd like to init it with 5 (non -consecutive) integers.
Right now it's declared in the .h>Interface, .h>#property, and .m>#synthesize.
How can I do this?
Thanks.
In your singleton's -init method, simply create and initialize it there:
- (id)init
{
_array = [[NSArray arrayWithObjects:[NSNumber numberWithInt:5], [NSNumber numberWithInt:50], [NSNumber numberWithInt:3.72], [NSNumber numberWithInt:5], [NSNumber numberWithInt:96], nil] retain];
return self;
}

How to store enum values in a NSMutableArray

My problem is since an enum in objective-c essentially is an int value, I am not able to store it in a NSMutableArray. Apparently NSMutableArray won't take any c-data types like an int.
Is there any common way to achieve this ?
typedef enum
{
green,
blue,
red
} MyColors;
NSMutableArray *list = [[NSMutableArray alloc] initWithObjects:
green,
blue,
red,
nil];
//Get enum value back out
MyColors greenColor = [list objectAtIndex:0];
Wrap the enum value in an NSNumber before putting it in the array:
NSNumber *greenColor = [NSNumber numberWithInt:green];
NSNumber *redColor = [NSNumber numberWithInt:red];
NSNumber *blueColor = [NSNumber numberWithInt:blue];
NSMutableArray *list = [[NSMutableArray alloc] initWithObjects:
greenColor,
blueColor,
redColor,
nil];
And retrieve it like this:
MyColors theGreenColor = [[list objectAtIndex:0] intValue];
A modern answer might look like:
NSMutableArray *list =
[NSMutableArray arrayWithArray:#[#(green), #(red), #(blue)]];
and:
MyColors theGreenColor = ((NSInteger*)list[0]).intValue;
Macatomy's answer is correct. But instead of NSNumber I would suggest you use NSValue. That is its purpose in life.
NSMutableArray *corners = [[NSMutableArray alloc] initWithObjects:
#(Right),
#(Top),
#(Left),
#(Bottom), nil];
Corner cornerType = [corner[0] intValue];
You can wrap your enum values in a NSNumber object:
[NSNumber numberWithInt:green];
To go with NSNumber should be the right way normally. In some cases it can be useful to use them as NSString so in this case you could use this line of code:
[#(MyEnum) stringValue];

Ask about int array in Objective-C

Code below is a simple c# function return an int array.
I would like to know how to convert it to Objective-C
private int[] test()
{
int[] a = new int[2];
a[0] = 1;
a[1] = 2;
return a;
}
The following code should work:
- (NSArray *)test {
NSArray *a = [NSArray arrayWithObjects:[NSNumber numberWithInt:1], [NSNumber numberWithInt:2], nil];
return a;
}
Note that if we created the NSArray using [[NSArray alloc] initWithObjects:blah, blah, nil];, we'd have to explicitly autorelease the array before returning it in order to avoid a memory leak. In this case, however, the NSArray is created using a convenience constructor, so the array is already autoreleased for us.
Second Question:
Try this:
- (NSMutableArray *)test:(int)count {
NSMutableArray *a = [[NSMutableArray alloc] init];
for (int i = 0; i < count; i++) {
[a insertObject:[NSNumber numberWithInt:0] atIndex:i];
}
return [a autorelease];
}
A bit dummy example:
- (NSArray*) test{
return [NSArray arrayWithObjects:[NSNumber numberWithInt:1], [NSNumber numberWithInt:2], nil];
}
Some notes:
NSArray is a immutable type - so if you want to add/remove values you should use NSMutableArray instead
You can store only objects in NSArray so you need to wrap them into NSNumber (or another obj-c type)
Obj-c is a superset of C so you can freely use c-arrays in you obj-c code if you want
Or an alternative path would be to use normal c code (is allowed in objective c):
int a[2]={1, 2};
Or in a function:
int *somefunc(void){
static int a[2]={1, 2};
return b;
}
There are two kinds of array in Objective-C: standard C arrays and Cocoa NSArrays. C arrays hold primitive ints but are quite troublesome due to the limitations of C. NSArrays have to hold objects, but you can just wrap ints in NSNumbers and get the int value back out when you need it.
NSArray *array = [NSArray arrayWithObjects:[NSNumber numberWithInt:1], [NSNumber numberWithInt:500], [NSNumber numberWithInt:12000], nil];

Iphone Object C - Data,Objects and Arrays

So I'm a Flash guy and I'm trying to convert the following code to Object C:
var slot:Object = new Object();
slot.id = i;
slot.xPos = 25*i;
slot.yPos = 25*i;
slot.isEmpty = False;
// push object to array
arrGrid.push(slot);
Later I can override like:
arrGrid[0].isEmpty = True;
I can't seem to find a reference to creating generic objects in Object C. Can someone help?
Well assuming you are doing something with the iphone or mac in cocoa you can simply subclass NSObject (the base class in objective-c).
You need a .h and .m so for you example it would be something like:
(Note that I used slotId instead of id because id is a keyword in objective-c)
Slot.h
// Slot.h
#interface Slot : NSObject {
NSInteger slotId;
float xPos;
float yPos;
BOOL empty;
}
#property NSInteger slotId;
#property float xPos;
#property float yPos;
#property BOOL empty;
#end
// Slot.m
#import "Slot.h"
#implementation Slot
#synthesize slotId;
#synthesize xPos;
#synthesize yPos;
#synthesize empty;
#end
That defines a simple Slot object with 4 properties which can be accessed using dot notation such as:
s = [[Slot alloc] init];
s.empty = YES;
s.xPos = 1.0;
s.yPos = 1.0;
There are a lot of variations for which data types you use and how you define the properties, etc depending on what kind of data you are dealing with.
If you wanted to add a slot object to an array one simple example:
// create an array and add a slot object
NSMutableArray *arr = [NSMutableArray array];
Slot *slot = [[Slot alloc] init];
[arr addObject:slot];
// set the slot to empty
[[arr objectAtIndex:0] setEmpty:YES];
If you're only using this Object instance to store named values, you can use an instance of NSMutableDictionary instead, although you'll need to wrap your integer values with NSNumber instances:
NSMutableDictionary * obj = [NSMutableDictionary dictionary];
[obj setObject: [NSNumber numberWithInt: i] forKey: #"id"];
[obj setObject: [NSNumber numberWithInt: i*25] forKey: #"xPos"];
[obj setObject: [NSNumber numberWithInt: i*25] forKey: #"yPos"];
[obj setObject: [NSNumber numberWithBool: NO] forKey: #"isEmpty"];
Then you'd add these to an NSMutableArray allocated using [NSMutableArray array] or similar:
[array addObject: obj];
To get the integer/boolean values out of the dictionary, you'd do the following:
int i = [[obj objectForKey: #"id"] intValue];
BOOL isEmpty = [[obj objectForKey: #"isEmpty"] boolValue];