I've got a managed object with an NSNumber that's just a Boolean value. When the user clicks a button I want to toggle that.
self.item.completed = [NSNumber numberWithBool:![self.item.completed boolValue]];
Is there a cleaner (or perhaps just more compact) way that I'm missing?
There is little you can do to the process of producing the negated value, but you can make the syntax of invoking it look less bulky by hiding your code in a category:
#interface NSNumber ( NegateBoolean )
-(NSNumber)negateBool;
#end
#implementation NSNumber ( NegateBoolean )
-(NSNumber)negateBool{
return [NSNumber numberWithBool:![self boolValue]];
}
#end
Now you can use the new method like this:
self.item.completed = [self.item.completed negateBool];
You could also set up an NSArray with inversions, and use it as follows:
NSArray *inversions = [NSArray arrayWithObjects:[NSNumber numberWithBool:YES], [NSNumber numberWithBool:NO], nil];
self.item.completed = [inversions objectAtIndex:[self.item.completed boolValue]];
You could consider setting up a "wrapper" getter and setter on self.item for a property, maybe called completedValue, that deals in BOOLs instead of NSNumbers. Might look a little like:
- (BOOL)completedValue {
return [self.completed boolValue];
}
- (void)setCompletedValue:(BOOL)value {
self.completed = [NSNumber numberWithBool:value];
}
Then your call just becomes:
self.item.completedValue = !self.item.completedValue;
Another way to approach this without the use of additional category method on NSNumber is to use the ternary operator and the NSNumber boolean literals:
self.item.completed = self.item.completed.boolValue ? #NO : #YES;
This should work with any recent version of Xcode but in particular it requires LLVM v4.0 or clang v3.1.
Related
How do I check if two arrays have one specific object that is not related at one common index for both arrays in Objective-C?
if ([[Array1 objectAtIndex:SameIndex] containsObject:String1] && [[Array2 objectAtIndex:SameIndex] containsObject:String2]) {
}
When I think of it, I may have to use a loop instead of an if statement.
Any help would be greatly appreciated.
The isEqual method allows you to compare two objects. You could do something similar to:
NSArray *array1 = #[[NSNumber numberWithInteger:10],
[NSNumber numberWithInteger:20],
[NSNumber numberWithInteger:30]];
NSArray *array2 = #[[NSNumber numberWithInteger:60],
[NSNumber numberWithInteger:70],
[NSNumber numberWithInteger:80]];
NSNumber *object1 = [NSNumber numberWithInteger:20];
NSNumber *object2 = [NSNumber numberWithInteger:70];
NSUInteger sameIndex = 1;
if ([[array1 objectAtIndex:sameIndex] isEqual:object1] && [[array2 objectAtIndex:sameIndex] isEqual:object2]) {
// Do something
NSLog(#"Validation passed!");
}
That will compare the object stored at index sameIndex in array1 and array2 with object1 and object2 respectively.
EDIT: I changed my code snippet into a working example for you to better understand.
You can use a few method on NSArray to find the object, for example:
[Aarray1 indexOfObject:...]
[Aarray1 indexOfObjectIdenticalTo:...]
[Aarray1 indexOfObjectPassingTest:...]
After that just make sure that you have an index and if index exists you know that there is an object. You have to just slightly amended code from your question.
I'm need to store some bool values in NSMutableDictionary, so I've founded a solution: using a [NSNumber numberWithBool] to make an object from bool.
It's work fine with value YES, but with NO it sometimes work fine, and sometimes result is "Not an objective-c object".
MyCode:
$ //sometimes fine, but sometimes "not an objective-c object"
$ NSNumber* nsn = [NSNumber numberWithBool:NO];
I'm new to Objective-C, so i'm sorry if this is basic problem, but i really stuck with it.
Thanks for help.
The object returned by numberWithBool and initWithBool seems to be initializing the NSNumber by a string and when you map the object in a dictionary it takes NSValue which indeed is null. Hence the dictionary will say it as null.
Try either of:
NSObject * y1 = #(YES) ;
NSObject * n1 = #(NO) ;
NSObject * y2 = #YES ;
NSObject * n2 = #NO ;
Another example:
NSDictionary * testDict = #{
#"key1": #YES
, #"key2": #NO
} ;
BOOL b = [testDict[#"key1"] boolValue] ;
Dude. Why don't you just create your own class:
#interface Fool
{
bool _amIFool;
}
#property bool amIFool;
#end
#implementation
-(bool)amIFool
{
return _amIFool;
}
-(void)setAmIFool:(bool)amIFool
{
_amIFool = amIFool
}
#end
Then you can shove it in a dictionary. Above code is just an example. You can write something better....
EDIT: You can even write a comparator, so you could directly do comparisons and stuff. And even write a convenience method so it is easy to initialise...
EDIT: Just FYI, my initial implementation was called "Cool". But since I'm not cool, I chose "Fool". You can do either.
If I have a large NSDirectory typically from a parsed JSON-object I can access this object with code like so:
[[[[[obj objectForKey:#"root"] objectForKey:#"key1"] objectAtIndex:idx] objectForKey:#"key2"] objectAtIndex:idz];
The line might be a lot longer than this.
Can I optimize this code in any way? At least make it easier to read?
This line will also generate a runtime-error if the object does not correspond, what is the most efficient way to avoid that?
If you were using -objectForKey: for everything you could use -valueForKeyPath:, as in
[obj valueForKeyPath:#"key1.key2.key3.key4"]
However, this doesn't work when you need to use -objectAtIndex:. I don't think there's any good solution for you. -valueForKeyPath: also wouldn't solve the problem of the runtime errors.
If you truly want a simple way to do this you could write your own version of -valueForKeyPath: (call it something else) that provides a syntax for specifying an -objectAtIndex: instead of a key, and that does the appropriate dynamic checks to ensure the object actually responds to the method in question.
If you want easier to read code you can split the line into several lines like this
MyClass *rootObject = [obj objectForKey:#"root"];
MyClass *key1Object = [rootObject objectForKey:#"key1"];
MyClass *myObject = [key1Object objectAtIndex:idx];
...
and so forth.
I think, you can create some array, that will contain full "path" to your object. The only thing, you need to store your indexes somehow, maybe in NSNumber, in this case you cannot use NSNumber objects as keys in your dictionaries. Then create a method, that will return needed object for this given "path". smth like
NSMutableArray* basePath = [NSMutableArray arrayWithObjects: #"first", [NSNumber numberWithInt:index], nil];
id object = [self objectForPath:basePath inContainer:container];
- (id) objectForPath:(NSMutableArray*)basePath inContainer:(id)container
{
id result = nil;
id pathComponent = [basePath objectAtIndex: 0];
[basePath removeObjectAtIndex: 0];
// check if it is a number with int index
if( [pathComponent isKindOfClass:[NSNumber class]] )
{
result = [container objectAtIndex: [pathComponent intValue]];
}
else
{
result = [container objectForKey: pathComponent];
}
assert( result != nil );
// check if it is need to continue searching object
if( [basePath count] > 0 )
{
return [self objectForPath:basePath inContainer: result];
}
else
{
return result;
}
}
this is just an idea, but I hope you understand what I mean. And as Kevin mentioned above, if you don't have indexes, you can use key-value coding.
Don't know if it can suit you, but you could also give a try to blocks, I always find them very convenient. At least they made code much more readable.
NSArray *filter = [NSArray arrayWithObjects:#"pathToFind", #"pathToFind2",nil];
NSPredicate *filterBlock = [NSPredicate predicateWithBlock: ^BOOL(id obj, NSDictionary *bind){
NSArray *root = (NSArray*)obj;
// cycle the array and found what you need.
// eventually implementing some sort of exit strategy
}];
[rootObject filteredArrayUsingPredicate:filterBlock];
I love the shorthand handling of string literals in Objective C with the #"string" notation. Is there any way to get similar behavior with NSNumbers? I deal with numbers more and it's so tedious having [NSNumber numberWithWhatever:] calls everywhere. Even creating a macro would work, but my knowledge of how best to do that is limited.
Since nobody has mentioned this... If you need to wrap a value in an NSNumber, the NSNumber literal syntax is as follows.
int val = 13;
NSNumber *numVal = #(val);
As of Clang v3.1 you can now use Objective-C literals.
NSNumber *fortyTwo = #42; // equivalent to [NSNumber numberWithInt:42]
NSNumber *fortyTwoUnsigned = #42U; // equivalent to [NSNumber numberWithUnsignedInt:42U]
NSNumber *fortyTwoLong = #42L; // equivalent to [NSNumber numberWithLong:42L]
NSNumber *fortyTwoLongLong = #42LL; // equivalent to [NSNumber numberWithLongLong:42LL]
So, answering your specific question:
[Tyler setArms:[[[NSNumber alloc] initWithInt:1] autorelease]];
Can now be written as:
[Tyler setArms:#1];
There are also literals for arrays and dictionaries, but they are beyond the scope of this question.
To take advantage of literals in Xcode you'll need at least version 4.4 -- this comes with Apple's LLVM 4.0 compiler.
I'm using a macro like
#define N(x) [NSNumber numberWithInt: x]
wich leads to code like
[N(123) intValue];
update:
One should be aware of the CPU and memory consumption of such a macro. While the #"…" strings are static compiler generated strings of the constant string class (depends on foundation maybe NSConstantString in Cocoa?) the macros create code which is evaluated at runtime and therefore create a new object every time they are called.
Xcode 4.4 has introduced the Clang features that rjstelling mentioned for literals for NSNumber, NSArray and NSDictionary. The syntax is simple:
//Number literal
NSNumber *pi = #3.14;
//Array literal
NSArray *primes = #[ #2, #3, #5, #7, #11 ]; //No nil terminator needed
//Dictionary literal
NSDictionary *dict = #{
#"key1": #42,
#"key2": #"Another key",
#3: #"A NSNumber key"
}; //No nil terminator, stored in "key:value," format
I have a string I want to parse and return an equivalent enum. I need to use the enum type elsewhere, and I think I like how I'm defining it. The problem is that I don't know a good way to check the string against the enum values without being redundant about the order of the enums.
Is there no option other than a big if/else?
typedef enum {
ZZColorRed,
ZZColorGreen,
ZZColorBlue,
} ZZColorType;
- (ZZColorType)parseColor:(NSString *)inputString {
// inputString will be #"red", #"green", or #"blue" (trust me)
// how can I turn that into ZZColorRed, etc. without
// redefining their order like this?
NSArray *colors = [NSArray arrayWithObjects:#"red", #"green", #"blue", nil];
return [colors indexOfObject:inputString];
}
In Python, I'd probably do something like the following, although to be honest I'm not in love with that either.
## maps url text -> constant string
RED_CONSTANT = 1
BLUE_CONSTANT = 2
GREEN_CONSTANT = 3
TYPES = {
'red': RED_CONSTANT,
'green': GREEN_CONSTANT,
'blue': BLUE_CONSTANT,
}
def parseColor(inputString):
return TYPES.get(inputString)
ps. I know there are color constants in Cocoa, this is just an example.
try this: Map enum to char array
Pseudo code.. untested.
int lookup(const char* str) {
for(name = one; name < NUMBER_OF_INPUTS; name++) {
if(strcmp(str, stats[name]) == 0) return name;
}
return -1;
}
A more objective-c'ish version of the code could be:
// build dictionary
NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
for(i=0; i<number_of_strings; i++) {
[dict setObject:[NSNumber numberWithInteger:i] forKey:[NSString stringWithUTF8String:names[i]]];
}
// elsewhere... lookup in dictionary
id obj = [dict objectForKey:name];
if(obj) return [obj intValue];
return -1;
This has already been answered: Converting between C enum and XML
Basically, you wind up defining corresponding strings when you define your enum, and then you use a category on NSArray so that you can do this:
static NSArray* colorNamesArray = [[NSArray alloc] initWithObjects:colorNames];
//colorNames is a nil-terminated list of string literals #defined near your enum
NSString* colorName = [colorNamesArray stringWithEnum:color];
//stringWithEnum: is defined with a category
Sure, the #define is a little ugly, but the code above, which is what you'll work with most of the time, is actually pretty clean.
I was never satisfied with any of the suggestions. (But I appreciate the effort that went into them.) I tried a few of them but they didn't feel good or were error-prone in practice.
I ended up created a custom dictionary to map integers to strings which feels a lot better because it's Cocoa through and through. (I didn't subclass NSDictionary in order to make it harder to misuse.)
#interface ZZEnumDictionary : NSObject {
NSMutableDictionary *dictionary;
}
+ (id)dictionary;
+ (id)dictionaryWithStrings:(id)firstString, ...;
- (NSString *)stringForInt:(NSInteger)intEnum;
- (NSInteger)intForString:(NSString *)stringEnum;
- (BOOL)isValidInt:(NSInteger)intEnum;
- (BOOL)isValidString:(NSString *)stringEnum;
- (BOOL)stringEquals:(NSString *)stringEnum intEnum:(NSInteger)intEnum;
- (BOOL)setContainsString:(NSSet *)set forInt:(NSInteger)intEnum;
- (NSArray *)allStrings;
#end
#interface ZZEnumDictionary ()
- (void)setInt:(NSInteger)integer forString:(NSString *)string;
#end