Check if a BOOL is set (can't be done with ==nil) - iphone

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

Related

How can i get the property of NSObject using NSString [duplicate]

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];

Iphone: Replace functions using reflection

I have a small function which I want to rewrite, so that function is valid for every class.
At the moment I have 10 of the same functions which all work same but every function is for another class.
I know, that I have to do it with reflections, but I am not so sure how to do it.
I already read this link:
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html
The functions I am talking about are:
-(NSCountedSet *)MissionGetReferecedNested:(id)modelObject
{
setOfObjects = [[NSCountedSet alloc]initWithArray:modelObject.MissionSectionList];
return setOfObjects;
}
-(NSCountedSet *)MissionGetSectionReferecedNested:(id)modelObject
{
setOfObjects = [[NSCountedSet alloc]initWithArray:modelObject.DamageAccountList];
return setOfObjects;
}
MissionSectionList and DamageAccountList are both NSMutableArrays from two different classes.
Is it possible to see if a class consists a NSMutableArray and if yes then it should call the .... modelObject.MyMutableArray?
You can use reflection like this:
- (NSCountedSet *)MissionGet:(id)modelObject
{
SEL propertySelector = NULL;
if ([modelObject respondsToSelector:#selector(MissionSectionList)]) {
propertySelector = #selector(MissionSectionList);
} else if ([modelObject respondsToSelector:#selector(DamageAccountList)]) {
propertySelector = #selector(DamageAccountList);
}
if (!propertySelector) {
[NSException raise:#"Invalid modelObject value" format:#"Model object %# does not contain any recognised selectors", modelObject];
}
return [[NSCountedSet alloc] initWithArray:[modelObject performSelector:propertySelector]];
}
But a more common technique among cocoa programmers would be:
- (NSCountedSet *)MissionGet:(id <MyCustomProtocol>)modelObject
{
return [[NSCountedSet alloc] initWithArray:[modelObject missionArray]];
}
Where you would accept any object which confirms to the protocol MyCustomProtocol. The protocol is defined in a header files somewhere, using:
#protocol MyCustomProtocol
#property (readonly) NSArray *missionArray;
#end
And then in each of your classes, declare it as implementing the protocol:
#interface MissionSectionListClass <MyCustomProtocol>
And add a method implementation:
#implementation MissionSectionListClass <MyCustomProtocol>
- (NSArray *)missionArray
{
return self.MissionSectionList;
}
#end
Using protocols is a bit more code, but it's the "right" way to go. It allows you to add support for new classes, without any change to your MissiongGet... method.
More info about protocols: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProtocols.html
EDIT : Cleared all my answer to this :
I think it's not possible to check if a class has a member variable of specified type. You can only check if a class has a specified method.
So, in this case it will be best if you make all your NSMutableArray list the same name, and then create a declared property for this list, and then do a respondsToSelector in your ...GetReferencedNested method.
So, for example, in all of your class create this property :
#property (nonatomic, retain) NSMutableArray * list;
and then in the ..MissionGetReferencedNested method :
if ([modelObject respondsToSelector:#selector(list)])
...
Correct me if i'm wrong...
In terms of style I'd also follow Abhi's suggestion.
But if you really want to inspect a class that you are stuck with and, for example build a NSCountedSet with the first NSMutableArray variable you can find, you could do it like this:
#import "Utilities.h"
#import <Foundation/Foundation.h>
#import <objc/objc-runtime.h>
#implementation Utilities
+ (NSCountedSet*)initCountedSetWithFirstArrayinObject:(id)someObject {
unsigned int c;
Ivar *ivar_arr = class_copyIvarList([someObject class], &c);
for (unsigned int i = 0; i < c; i++) {
if ([#"#\"NSMutableArray\"" isEqualToString:
[NSString stringWithCString:ivar_getTypeEncoding(ivar_arr[i]) encoding:NSUTF8StringEncoding]
]) {
return [[NSCountedSet alloc] initWithArray:object_getIvar(someObject, ivar_arr[i])];
}
}
return nil;
}
#end
Of course this has very limited real world use because it depends on you knowing that the first array will be the one you're interested in.
I think I have to go with the runtime type editing.(http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html)
The idea with the protocols was good but there I have to change a lot of things in the classes.(which is not possible/allowed) for me. My intension was only to change the functions so that I have only one function for all classes.
I think with the runtime type editing I can check what classes and attributes I have (?) Am I right?
Did somebody already work with runtime type editing?

iPhone Core Data crash with ARC

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"];
}

Storing NSNumber in NSMutableArray

I have the following declarations in my model.h:
#interface Model: NSObject {
NSMutableArray *myMutableArray;
....
}
#property (nonatomic) double myDouble;
The corresponding #synthesize in model.m:
#synthesize myDouble;
I then have the following setter override:
-(void) setMyDouble: (double) newDouble{
myDouble = newDouble;
[myMutableArray addObject:[NSNumber numberWithDouble:myDouble]];
}
Putting a break point after the array assignment, the debugger shows the following for myMutableArray:
myMutableArray = (_NSArrayM *) 0x631c450 1 objects
0 = (NSCFNumber *) 0x631c6a0
So, my double does not seem to be properly getting into the array. I have subsequent assignments to this array for NSStrings that show up fine in the debugger. The values for both myDouble and newDouble are good (usually just an integer).
I've read several threads on assigning doubles to NSMutableArrays and haven't discovered anything out of the ordinary. Any guidance would be appreciated.
Update
It appears that the code is correct, but I failed to understand that the debugger shows the NSNumber's address rather than its value. Thank you everyone for responding, much appreciated! :)
It seems you are confusing with 0 in 0 = (NSCFNumber *) 0x631c6a0. That 0 is the index of the NSNumber in the array. If you retrieve the objects from the array and print it in NSLog, it would show you the correct values. Nothing seems to be wrong in your code.
You forget to allocate your mutable array. Debug your app and see if the array is allocated or not.
Edit
Change your function name to something else and see the magic.

Sharing variables amongst 2 ViewControllers

Here is a simple one for you guys . I'm defining a class to store variables in so I can reuse those variables in different ViewControllers .
Here is how I do it, it`s obviously not working ( that's why I'm asking a question ... ):
I declare a class :
VariableStore.h
#interface VariableStore : NSObject {
int evTe;
}
#property (nonatomic) int evTe;
+ (VariableStore *)shareInstance;
#end
VariableStore.m
#implementation VariableStore
#synthesize evTe;
+ (VariableStore *)sharedInstance {
static VariableStore *myInstance = nil;
return myInstance;
}
#end
Now in my FirstViewController I want to set the value for evTe :
[[VariableStore sharedInstance] setEvte:2];
NSLog(#"value testing, %i", evTe);
And this keeps on returning 0 unfortunately, Im obviously missing something important here but I can't figure out what it is .
Later on Id like to set the value for evTe here in the FirstViewController and then reuse it back in the SecondViewController ..
You are setting your shared instance to nil and then returning it:
static VariableStore *myInstance = nil;
return myInstance;
A nil instance won't hold your variable. It's nil.
First off you shouldn't be using a singleton to pass around variables. If you're going to do that then you might as well just use global variables instead (don't do that either by, the way). Second, if you insist on using a singleton, you need to read up on how to use them.
Finally, if you want to pass variables between view controllers, you either need another view controller that is a parent to the two to facilitate passing data between them, or one needs to call the other and take the first one or its data as a parameter.
Well, you're asking for the value of evTe without calling the object to which it belongs. Try this:
NSLog(#"value testing, %i", [[VariableStore sharedInstance] evTe]);
If you keep using the singleton for a number of times, you might want to do:
VariableStore *vStore = [VariableStore sharedInstance];
so you can do:
[vStore setEvTe:2];
NSLog(#"value testing, %i", [vStore evTe]);
And look out for what Matt said about nilling your singleton ;)
I think in nslog you should output not just evTe, but [[VariableStore sharedInstance] evTe].
First, you have to declare the static variable outside the function, in a way both controllers can access.
static VariableStore* myInstance = nil;
The singleton sharedInstance should be:
if(myInstance == nil)
{
myInstance = [[VariableStore] alloc] init];
}
return myInstance;