This is my first time trying to use both ARC and Core Data. I can't seem to figure out why my code is crashing.
in the .h I have:
#interface Foo : NSObject {
}
#property (nonatomic,strong) NSString *name;
#property (nonatomic,strong) NSString *email;
#property (nonatomic) BOOL myBool;
#property (nonatomic) float myFloat;
in the .m
#implementation User
#dynamic name;
#dynamic email;
#dynamic myBool;
#dynamic myFloat;
User *user = (User *)[NSEntityDescription insertNewObjectForEntityForName:#"User" inManagedObjectContext:[appDelegate managedObjectContext]];
[user setName:[[[dictionary objectForKey:#"user"] objectForKey:#"user"]objectForKey:#"name"]];
[user setEmail:[[[dictionary objectForKey:#"user"] objectForKey:#"user"]objectForKey:#"email"]];
[user setAuthorisation_token:[[[dictionary objectForKey:#"user"] objectForKey:#"user"]objectForKey:#"authentication_token"]];
[user setMyFloat:5]; <------ crash when set to anything other than 0 (eg,setting to FALSE will crash it).
[user setMyBool:FALSE]; <---- crash when set this to anything other than 0.
Basically whenever I try to use a type other than a string I am getting EXEC crash on that particular line. When I use strings for everything it is fine. In my.xcdatamodeld file I have myFloat set to FLOAT and myBool set to BOOLEAN
kill
error while killing target (killing anyway): warning: error on line 2184 of "/SourceCache/gdb/gdb-1708/src/gdb/macosx/macosx-nat-inferior.c" in function "void macosx_kill_inferior_safe()": (os/kern) failure (0x5x)
quit
Program ended with exit code: 0
You can't use #dynamic for primitives (like float and BOOL) because Core Data won't create implementations for them.
So the reason why your code is crashing is because when you use #dynamic you are telling the compiler "I promise that an implementation for these getters and setters will be available at runtime". But since Core Data doesn't create them then your code tries to call methods that doesn't exist.
Instead there are two things you could do: Use an NSNumber for both the BOOL and the float or implement your own getters and setters.
Using NSNumber:
Core Data only uses objects and not primitives but you can specify boolean or float in the Model. When you call [user myFloat] you will actually get an NSNumber back with the float value inside it. To access the primitive you then call float f = [[user myFloat] floatValue];. The same thing goes for the boolean, it also gets stored in an NSNumber. So when you try to access it you will get back an NSNumber that you need to call BOOL b = [[user isMyBool] boolValue]; to get the primitive back.
The same thing goes the other way around, when setting myFloat and myBool, you need to store them inside an NSNumber, e.g. [user setMyFloat:[NSNumber numberWithFloat:f]]; and [user setMyBool:[NSNumber numberWithBool:b]];.
To use this approach you would have to change your last two properties to
#property (nonatomic, strong) NSNumber *myBool;
#property (nonatomic, strong) NSNubmer *myFloat;
but you can keep the #dynamic for both of them.
Implementing you own getters and setters:
For your convenience, you may want your "user" object to get and set the primitive types, float and BOOL, directly. In that case you should keep the properties as float and bool and in your implementation file (.m) remove the #dynamic lines for myFloat and myBool.
To implement the getter and setter you need to know a little about KVC/KVO and Core Data. In short: you need to tell the system when you are about to access or change a property and when yo u are done accessing or changing it, since Core Data won't do it for you. Between the "will access/change" and "did access/change" you are free to retrieve or modify the properties. One more caveat is that Core Data still cannot save the BOOL and float directly, so they need to be packaged into and unpackaged from NSNumbers when getting and setting.
Further, you can't call [self setValue:ForKey:]; or [self valueForKey:#""]; because that would cause the method you are in to call itself and throw you into an infinite loop. Core Data solves this use-case by allowing you to get and set the value without hitting your own implementation by calling [self setPrimitiveValue:ForKey:] and [self primiveValueForKey:]. Note: primiteValueForKey has nothing to do with primitive types (int, float, BOOL) but is just the name of the methods you use to get and set values in Core Data directly.
The implementation for your float and BOOL would look something like this:
- (float)myFloat
{
[self willAccessValueForKey:#"myFloat"];
float f = [[self primitiveValueForKey:#"myFloat"] floatValue];
[self didAccessValueForKey:#"myFloat"];
return f;
}
- (void)setMyFloat:(float)f
{
[self willChangeValueForKey:#"myFloat"];
[[self setPrimitiveValue:[NSNumber numberWithFloat:f] forKey:#"myFloat"];
[self didChangeValueForKey:#"myFloat"];
}
- (BOOL)isMyBool
{
[self willAccessValueForKey:#"myBool"];
BOOL b = [[self primitiveValueForKey:#"myBool"] boolValue];
[self didAccessValueForKey:#"myBool"];
return b;
}
- (void)setMyBool:(BOOL)b
{
[self willChangeValueForKey:#"myBool"];
[[self setPrimitiveValue:[NSNumber numberWithBool:b] forKey:#"myBool"];
[self didChangeValueForKey:#"myBool"];
}
Related
This question already has an answer here:
Objective-C get a class property from string
(1 answer)
Closed 9 years ago.
I'm developing for the iPhone. Is there any way to get a property using an NSString holding the property name? something like:
#interface MyLovelyClass : NSObject
#property (nonatomic) double test;
-(double) returnDoubleProperty:(NSString *) propertyName;
and then to call it
MyLovelyClass *mlc=[[MyLovelyClass alloc] init];
double value=[mlc returnDoubleProperty:#"test"];
I understand that if i have a limited number of properties, i can manually write if else statements that would return values for each input string. However, is there any way to achieve this programmaticaly?
You want to use KVC (key value coding) which does exactly what you describe, but you don't need to implement any methods for it to work. It does work with objects though so your double would be wrapped inside an NSNumber:
#property (nonatomic, strong) NSNumber *test;
NSNumber *value = [mlc valueForKey:#"test"];
Since properties are methods, you can call them through performSelector:. To make a selector from string use NSSelectorFromString. The double will be wrapped in an id object of type NSNumber, so you need to pull it back by calling doubleValue:
SEL toCall = NSSelectorFromString(#"test");
double value=[[mlc performSelector:toCall] doubleValue];
What I have read from the apple document retain will increase the retain count by 1 , and release will decrease by 1. This is very much clear to me.
But In the case of copy and retain i am a bit confused.
Let me explain with the code i am trying.
property ---
#property(nonatomic, retain) NSMutableString *a;
#property(nonatomic, copy) NSMutableString *b;
#synthesize a = _a ,b = _b
a=[[NSMutableString alloc]initWithString:#"Hello Ankit"];
NSLog(#"a memory location A - %p", &a );
b=[[NSMutableString alloc]initWithString:#"Hello Nigam"];
NSLog(#"a memory location B- %p", &b );
c= [[NSMutableString alloc]initWithString:#"Ankit Nigam"];
NSLog(#"a memory location C %p",&c);
NSMutableString *temp =[[NSMutableString alloc]initWithString:#"hey"];
NSLog(#"temp = %# %p",temp,&temp);
self.b = temp;
NSLog(#"B is now %# %p",self.b,&b);
self.a = temp;
NSLog(#"A is now %# %p",self.a,&a);
And i get the output as -- - -
2012-05-10 03:24:34.756 retainCountTest[2655:f803] a memory location A - 0x6d314fc
2012-05-10 03:24:34.757 retainCountTest[2655:f803] a memory location B- 0x6d31500
2012-05-10 03:24:34.764 retainCountTest[2655:f803] a memory location C 0x6d31504
2012-05-10 03:24:34.764 retainCountTest[2655:f803] temp = hey 0xbfffdd04
2012-05-10 03:24:34.764 retainCountTest[2655:f803] B is now hey 0x6d31500
2012-05-10 03:24:34.765 retainCountTest[2655:f803] A is now hey 0x6d314fc
But as per I understand from the Doc the retain object must have the same memory address , where as copy object will create a new object with different memory location.
Again when i change the logs to ---
self.b = temp;
NSLog(#"B is now %# %p",self.b,&_b);
self.a = temp;
NSLog(#"A is now %# %p",self.a,&_a);
It return me a complete different memory location for both the object.
2012-05-10 03:28:49.905 retainCountTest[2688:f803] a memory location A - 0x6d4a4ac
2012-05-10 03:28:49.906 retainCountTest[2688:f803] a memory location B- 0x6d4a4b0
2012-05-10 03:28:49.907 retainCountTest[2688:f803] a memory location C 0x6d4a4b4
2012-05-10 03:28:49.907 retainCountTest[2688:f803] temp = hey 0xbfffdd04
2012-05-10 03:28:49.908 retainCountTest[2688:f803] B is now hey 0x6d4a4c0
2012-05-10 03:28:49.908 retainCountTest[2688:f803] a is now hey 0x6d4a4bc
Can any help me to understand the complete concept of these retain and copy. Also why I am getting these unexpected results.
Thanks a lot.
A property is just a declaration that allows for setters, getters, and dot-syntax accessors (interface variable hiding).
It does absolutely nothing on its own but allow you to use -[myInstance myProperty] to get the variable or use -[myInstance setMyProperty:] to set it (yes, the method name is auto-assigned to -setProperty: and -property).
When declaring a property, you have three categories - thread locking, access control, and memory management. You can only pick one of the modifiers for each category and if you do not pick one, it's auto-assigned to one automatically.
#property (<thread locking>, <access control>, <memory management>) id property;
The first category can either be atomic or nonatomic. The atomic modifier forces an #synchronized(myInstance) lock on the variable, to allow thread safety. The nonatomic does not use a synchronized-block, and is NOT thread safe. If you do not use either, it is automatically set to atomic.
The second category can either be readonly or readwrite. The readwrite modifier allows the property to be modified as well, and allows auto-generation of the -setProperty: method. When the readonly modifier is used, you cannot use the -setProperty: method. You must use the internal variable from within the object to set the variable directly.
The third category can either be assign, retain, and copy. The assign modifier means the internal object pointer is set to the pointer passed to the -setProperty: message. The retain modifier assigns the passed pointer and passes a -retain to the object.
The copy modifier does a straight-up clone of the object- a new pointer to a new object at a new address in the memory. This sets the internal object pointer to the copy of the passed object, by calling -copy on the passed object. The default modifier is assign, and the compiler will warn you if you do not set the memory management category modifier on an object - because an assign modifier on an object is frowned upon (unless explicitly declared).
For an example on -copy, look at this:
- (void)setProperty:(GXMyObject *)property {
// This points to the original passed object.
GXMyObject *original = property;
// This points to a copy of the passed object.
CGMyObject *copied = [property copy];
// This points to yet another copy of the passed object-
// Independent of the other copies and original.
_property = [property copy];
// The anotherProperty is now different on this copy
// than on the original and the other copies.
_property.anotherProperty = 4;
// This will prove that they are all individual objects.
NSLog(#"%p, %p, %p", original, copied, _property);
}
There is an optional method name declaration modifier and is used like so: getter = myCustomPropertyGetter and setter = myCustomPropertySetter: (The colon : at the end of the setter method name is required because it denotes that an argument must be passed).
The second half of this is the property synthesizer or dynamizer. Once a property is declared (for example, myView) like so:
#property (nonatomic, retain) NSView *myView;
You would either: define the setter and getter yourself; #synthesize the setter and getter; #dynamic the property to say that it exists in a category or the main class, or may be added at runtime (not a fun idea, mind you, and could cause bad runtime exceptions).
The first example, writing the methods yourself would look like this:
// In Apple's LLVM 3.1 Compiler, instance variables can be added
// within {} below the #implementation as well as the #interface,
// and in private categories (#interface GXMyClass ()) like before.
#implementation GXMyClass {
// The internal object pointer is prefixed with an _ to avoid name confusions.
NSView *_myView;
}
- (NSView *)myView {
return _myView;
}
- (void)setMyView:(NSView *)myView {
_myView = [myView retain];
}
#end
The second example would be to auto-synthesize it using the #synthesize directive:
#implementation GXMyClass
// In the new Apple LLVM 3.1 Clang compiler, the = operator when used
// next to the #synthesize directive declares an internal private
// variable and automatically sets to that variable.
#synthesize myView = _myView;
// The internal variable name is now myOtherView, because we did not use the
// = operator to assign an internal variable name to the property.
#synthesize myOtherView;
#end
Under the last example, perhaps the most confusing, because it requires the use of the #dynamic directive, you require something of a category or a runtime method addition:
#interface GXMyClass (InternalMethods)
#end
#implementation GXMyClass
// The = assignment operator does not work here.
#dynamic myView;
#end
#implementation GXMyClass (InternalMethods)
- (NSView *)myView {
return [self methodThatReturnsAnNSView];
}
- (void)setMyView:(NSView *)myView {
[self methodThatAcceptsAnNSViewArgument:myView];
}
#end
The #property declaration requires one of the three above declarations to be present- it does not do anything on its own. What it DOES allow, however is dot-syntax accessors (Java-like accessors for setting and getting properties).
For example, #property (copy) NSString *myName; could be accessed using -[myObject myName] and set using -[myObject setMyName:].
Now it can be set using myObjectInstance.myName = #"Bob"; and gotten using myObjectInstance.myName. Utilizing all the above concepts, one could create an object such as this one:
// The GXBufferQueue is a queue which buffers all requests, till they are read
// asynchronously later. The backing store is an NSMutableArray to which all
// buffer writes are appended to, and from which the first object is pulled and
// returned when the buffer is read to.
#interface GXBufferQueue
#property (nonatomic, readwrite, copy, setter = write:, getter = read) id buffer;
+ (GXBufferQueue *)queue;
#end
#implementation GXBufferQueue {
// This queue is an internal array and is 'tacked on' to the #implementation
// so no others can see it, and it can be marked #private so subclasses cannot
// use it. It is also good code practice to have #interfaces composed of only
// #properties, setters, and getters, rather than expose internal variables.
NSMutableArray *_internalQueue;
}
+ (GXBufferQueue *)queue {
return [[[GXBufferQueue alloc] init] autorelease];
}
- (id)init {
if((self = [super init])) {
_internalQueue = [[NSMutableArray alloc] init];
}
}
- (void)write:(id)buffer {
[_internalQueue addObject:buffer];
}
- (id)read {
if(!(_internalQueue.count > 0)) return nil;
id buffer = [_internalQueue objectAtIndex:0];
[_internalQueue removeObjectAtIndex:0];
return buffer;
}
#end
Note: This code was in no way tested.
Now that you have a GXBufferQueue, all the following works:
GXBufferQueue *queue = [GXBufferQueue queue];
// Option One: using the traditional message syntax:
[queue write:#"This will be now added to the buffer."];
NSLog(#"Now the string written to the queue will be read \
and removed from the queue, like a stack pop. ", [queue read]);
// Option Two: using the new dot-syntax accessors:
queue.buffer = #"As clunky as this looks, it works the same as above.";
NSLog(#"These lines work just the same as the ones above: ", queue.buffer);
As you can see, there's a lot possible with properties and a lot more that can be done with them than just variable declaration. If there are any questions or anything the community would like me to add/rectify to/in the post, please leave a comment! :D
Yes, retainCount is useless-- don't call it-- and assuming that copy will always return a new instance is incorrect.
If an immutable object is sent copy, it will typically be implemented as:
- copy { return [self retain]; }
I.e. there is no need to make an actual copy since the contents can't change.
Of course, since you are mucking about with static, compiled into the binary, strings, the implementation is likely closer to:
- retain { return self; }
- copy { return self; }
- (void)release { ; }
- (void)dealloc { ; }
Maybe -- all of the above are implementation details that may change at any time. The bottom line, though, is that all of the above fulfills the contract of retain/release/copy/etc...
Icon is set as #property (nonatomic, retain) AHGridIcon *icon;
Usually i just do:
-(void)setIcon:(AHGridIcon *)iconLocal {
icon = iconLocal;
}
But i read a guide to getters setters and properties online which has lead me to believe that instead, this is right:
-(void)setIcon:(AHGridIcon *)iconLocal {
if (iconLocal != self.icon)
{
NSLog(#"local: %#", iconLocal);
NSLog(#"self.icon 1: %#", self.icon);
[iconLocal retain];
[icon release];
icon = iconLocal;
NSLog(#"self.icon 2: %#", self.icon);
}
}
The problem is, the original icon is staying put, it's not being replaced with the new icon. What am i doing wrong? Should i just revert to the usual way i do it?
You should use '#synthesize' unless you really need custom setter behavior.
like I posted in my comment:
the best way is to use #synthesize which will create a getter and a setter to with respect to the properties you wrote in your property (nonatomic, retain) => not threadsafe but fast getter and setter and a retaining (and also releasing) setter. If you dont need sophisticating stuff to do in your setter then you should not override the setter.
.h:
#property (nonatomic, retain) AHGridIcon *icon;
.m:
#implementation Something
#synthesize icon;
...
#end
The code you posted in your setter is nearly the same as the compiler would produce when only using synthesize.
Your usual way is not really nice because in your header is defined (in your property) that the setter is retaining but in your implementation you are overriding that correct setter which doesn't retain. It is nearly the same as the compiler would produce with an (nonatomic, assign) property.
But if you want to override your setter then it should look like the same as you wrote. For me it is working fine.
first retaining the new object
then releasing the old one
then assigning the local pointer to your new object
you can even omit your if but then it is really important that you first retain the new and then release the old objects (like you did - just want to mention that).
For solving your problem with an overriten setter: Your setter looks ok in my eyes. Have you also overriten the getter? If yes then post it here (you use it by calling self.icon in your log-call).
I've done a small test-program
#synthesize str;
- (void)setStr:(NSString *)localStr
{
if(str != localStr)
{
NSLog(#"old : %#", self.str);
NSLog(#"new1: %#", localStr);
[localStr retain];
[str release];
str = localStr;
NSLog(#"new2: %#", self.str);
}
}
and the output is fine:
old : (null)
new1: Hello
new2: Hello
old : Hello
new1: World
new2: World
for a day now I stare at the following routine and can't get my grips around it. I have a class such as:
MyClass.h
...
#interface MyClass : NSObject {
NSNumber *myNumber1;
NSNumber *myNumber2;
}
#property (nonatomic, retain) NSNumber *myNumber1;
#property (nonatomic, retain) NSNumber *myNumber2;
#end
and the m-file
#import "MyClass.h"
#synthesize myNumber1, myNumber2;
#implementation MyClass
-(id) init {
self = [super init];
NSLog(#"Retain Counts myNumber1: %d, myNumber2: %d", [myNumber1 retainCount], [myNumber2 retainCount]);
myNumber1 = [NSNumber inbitWithint:10];
myNumber2 = [NSNumber inbitWithint:2];
NSLog(#"Retain Counts myNumber1: %d, myNumber2: %d", [myNumber1 retainCount], [myNumber2 retainCount]);
return self;
}
...
I use this class as a globals container and instantiate it from every other class in my app using a
MyClass *myGlobals = [[MyClass alloc] init];
===>>> the weirdo >>>
Running the routine I have the following facinating console output:
Retain Counts (before) - myNumber1: 0, myNumber2: 0
Retain Counts (after) - myNumber1: 1, myNumber2: 26
How can that be?
Do not call `retainCount`
The return value of retainCount can only be considered accurate if you are calling it on an instance of a class you wrote and you have never ever not even once passed said instance to any API provided by the system.
The absolute retain count is an implementation detail for which you might not have any control.
Assuming, for the moment, that your code was typed and, thus, the errors are not really in your original code...
NSNumber caches a subset of common values. That is, for some numeric values, there is a single instance of NSNumber that is returned for all requests to retrieve an NSNumber instance wrapping that number.
If this is your actual code, it shouldn't work at all, it should simply crash. If not, you should cut and paste your actual code.
However, a couple of things.
First, if you use an NSNumber as an ivar, like anything else, you must take ownership of it. If you plan to use a convenience constructor, you must either assign it using the property on self, or send it an explicit retain message.
Second, you typed something like initWithInt: here. If you are actually using that message, then you have never actually allocated the number in the first place. You must replace this with one of the following:
myNumber1 = [[NSNumber alloc] initWithInt:10]; // explicitly create the number
myNumber1 = [[NSNumber numberWithInt:10] retain]; // take ownership through retain
[self setMyNumber1:[NSNumber numberWithInt:10]]; // use the property accessors to deal with ownership and the convenience constructor to create the number
However you choose to do it, you must at some point take ownership of the object.
You should never even look at retainCount as it carries little significance anyway. The reason you see the count of 26 is that probably somewhere in the frameworks (or even in your own app) other instances of NSNumber exist that are created with the same int 2. An NSNumber is immutable, and so as an optimization NSNumber probably just gives you back an instance it has created earlier. As long as you don't look at retainCount it doesn't matter to you.
how do i check if a BOOL is set in objective-c (iphone)?
i know that it can be done with an int or float this way:
NSNumber *Num = [prefs floatForKey:#"key"];
for example
You can't. A BOOL is either YES or NO. There is no other state. The way around this would be to use an NSNumber ([NSNumber numberWithBool:YES];), and then check to see if the NSNumber itself is nil. Or have a second BOOL to indicate if you've altered the value of the first.
Annoyingly, Objective-C has no Boolean class. It certainly feels like it should and that trips a lot of people up. In collections and core data, all bools are stored as NSNumber instances.
It's really annoying having to convert back and forth all the time.
By default, a bool value is set to 0 in Objective-C, so you don't need to check if your bool value is nil anytime.
You can use something like this instead...
#import Foundation;
#interface CSBool : NSObject
+ (CSBool *)construct:(BOOL)value;
#property BOOL value;
#end
#import "CSBool.h"
#implementation CSBool
+ (CSBool *)construct:(BOOL)value {
CSBool *this = [self new];
this.value = value;
return this;
}
#end