Check if a variable belongs to an enum value - objective-c

Is there any way to assign a set of values to an enum and check wether a variable has its value in that enum in objective-c.
Something like getting the index of an object in an array if the object is present in an array. I want to give a common behavior, when certain indexes(may not be in order) tapped in my table view, want to avoid if-ing all the indexes, hope I can use enum style.

Objective-C, like most programming languages, doesn't provide a "type membership" test for primitive types - just for object types (e.g. isKindOfClass:) - so using an enum won't solve your problem.
However given that you are thinking of an enum in the first place it sounds like you have a small fixed set of values you wish to check for. In that case you can just use a static array, e.g. something like:
static NSUInteger indices[] = { 2, 42, 57 };
The number of values in such an array is given by sizeof(indices) / sizeof(NSUInteger and you can write a simple loop or binary search to test for membership.
If you wish to use objects then NSSet is a good choice, if the numbers will vary during execution then NSMutableSet. E.g.
NSSet *indices = [NSSet setWithObjects:#2, #42, #57, nil];
and you test for membership using member::
if ([indices member:#indexToTest] != nil) ...
(Note: unlike NSArray the specification for containsObject: for NSSet does not say it uses isEqual:, hence the use of member: here.)

You can't use an enum for that, because you can't enumerate them or call sth. like contains on them. If I understand your correctly I think the straight forward way to do that would be to just use an NSArray to store the indices you care about. Say you want to recognize the indices 2,6 and 14:
NSArray *indices = [NSArray arrayWithObjects: #2, #6, #14, nil];
(The # is necessary because an NSArray can only store objects. The # turns the integers into NSNumber instances.
Then to check if the currently selected index is in it you use:
int indexToCheck = ...;
BOOL indexIsInArray = [index containsObject:#(indexToCheck)];
If your looking for a more 'fancy' (and faster) way to that, you could use bit operations (again using 2,6 and 14 as example):
int indices = 1 << 2 | 1 << 6 | 1 << 14;
and then to check:
int indexToCheck = ...;
BOOL isValid = (1 << indexToCheck) & indices;
where isValid is true when the indexToCheck in one of your indices.

No, internally enums are based on integers, and the mapping happens at compile time. So you need a specific check for every enum type (if they are consecutive numbers, a ">" and "<" check will do).

Related

Return a key : value pair from a method for use in NSDictionary

I understand I can return an NSDictionary by doing
- (NSDictionary *)keyWithValue {
return #{#"key" : #"value"};
}
but how can I return that without the enclosing #{} dictionary?
There is no tuples in Objective C unlike in Swift, Python etc. So the common way to return 2 different objects is to return an array or a dictionary.
You also can try something like:
- (NSString *)keyWithValue:(NSString**)value {
*value = #"value";
return #"key";
}
It should be used following way:
NSString *v;
NSString *k = [self keyWithValue:&v];
// now v contains #"value"
Objective-C, like C before it, doesn't allow the return of multiple values from a method. (Essentially, although a method or function can accept any number of arguments as input, it can only have a single return value.) There are historical and implementation reasons for this design but it can be frustrating when you simply have a pair/tuple to return.
If you have a method that has two distinct "results" that you need to return to the caller, you have a few choices. The very simplest in your case is to do something like what you are doing here and "wrapping" the values in a dictionary. You could similarly wrap them in a two-value array (which is a little less good since it relies on an implicit contract between caller and callee that there will be exactly two items in the array).
However, a clean and fairly standard approach here would be to create a small class with only two properties on it, and create, fill in, and return that instance with your pair of values. This arguably uses less runtime overhead than a collection object, and has the nice benefit of being semantically explicit and easy to understand for anyone else looking at it.
(There is yet another way, which involves passing pointers as arguments that are "outparams", but that's only idiomatic in rare circumstances in ObjC and I wouldn't recommend it here.)
There is no way to return a key value pair without a dictionary because that is the definition of the dictionary data structure. From apple docs:
The NSDictionary class declares the programmatic interface to objects that manage immutable associations of keys and values
You access the value with
[myDictionary objectForKey:#"myKey"];
If you want to use the returned key-value pair in another dictionary
NSMutableDictionary *otherDict = [NSMutableDictionary alloc] init];
[otherDict setObject:[myDictionary objectForKey:#"myKey"] forKey:#"myKey"];

Creating an array based on multiple conditions

This is more of a logic question. I wanted to see different approaches.
I am trying to create a filter array based on multiple criteria. Let's say I have 4 boolean criteria,
I will set these with a simple toggle button.
NSObject* A; BOOL booleanA TRUE;
NSObject* B;BOOL booleanB FALSE;
NSObject* C;BOOL booleanC TRUE;
NSObject* D;BOOL booleanD FALSE;
What I want to achieve is to end up with an array with objects with TRUE boolean values like :
NSArray: {A, C}
I was going to use the most straightforward approach:
if(booleanA)[array addObject:A];
if(booleanB)[array addObject:B];
if(booleanC)[array addObject:C];
if(booleanD)[array addObject:D];
Looks fine to me, but maybe you can come up with something different and simpler. I literally cant think of any other way.
You look for an algorithmic solution. Right now, you manually transform 4 (unrelated, albeit similar named) BOOLs into 1 array. You can only write an algorithm when there's a 1:1 match, instead of a N:1 transformation. So I suggest you try to put booleanA to booleanD in a container instead of fiddling around with seemingly unrelated variables.
If you put the booleans into an array with fixed positions, using consts or macros for the indexes (booleans[B_INDEX]), you can write an algorithm to transform the truthiness at index i into letter A+i, so to speak.
If you use a small collection class instead, you can even get rid of handling arrays and matching indexes.
I would prefer a collection class so that the other class using this stuff doesn't get too bloated. The four lines you show look similar, but since the BOOLs have nothing in common but their name, you won't be able to write an algorithm yet. Encapsulating an algorithm like #user3571918 proposed will hide the matching from your calling class. Also, it hides the fact that 4 lines of manual transformation may have turned into a 30+ lines value object or service class :)
Will using a more complex, algorithmic solution pay off? I think this is the case if you plan on adding more switches later so you don't have to change the calling class just because its data representation was extended.
Example code
Here's an example algo I'd put into a utility class to hide the fact that the number of elements is fixed from other classes.
NSArray *booleans = #[#0, #1, #0, #1]; // array representation
NSArray *transformations = #[#"A", #"B", #"C", #"D"]; // matching utility
NSMutableArray *result = [NSMutableArray array];
[booleans savedArray enumerateObjectsUsingBlock:^(NSNumber *boolean, NSUInteger idx, BOOL *stop) {
BOOL isToggled = [boolean booleanValue];
id transformation = transformations[idx];
if (isToggled)
{
[result addObject:transformation];
}
}];
// result will be: #[#"B", #"D"];
How you assemble booleans depends on the code you already have. Maybe handing the toggle switches over as a variadic argument list to a utility method works, maybe it will be simpler.
The issue is that a Boolean operator is not an object. You might be better off utilizing #0 and #1 for your purposes, and no matter what you'd have to objectify your Boolean value to place in NSArray. The workaround for that is to utilize a C array, however, since you asked for a more convenient way to derive your answer utilizing Objective-C, I'll stick with that.
Basically, I think your question boils down to 'how to enumerate NSArray' and there are some options. Here's a good high level resource regarding NSArray. There are other ways to do it, and especially flexible with enumerateWithBlock as described here previously.
With fast enumeration you can have code that may look similar to the following:
NSArray* array = #[#0, #1, #0, #1];
for (NSNumber* number in array) {
if ([number isEqualToNumber:#0]) {
// action here
return;
}
// else action here
}

Create an NSRange with a given minimal and maximal value

I have a collection of int64_t values that I need to make an index set out of. I previously have used:
NSIndexSet *set = [NSIndexSet indexSetWithRange:NSMakeRange(location, length)];
to make index sets, but this time its unclear to me how I would do this based on the information I have.
Specifics: I have a collection of values. I know the highest value in the collection, the lowest value in the collection and the number of values in the collection. However, the values are not necessarily consecutive.
For example, if I have the following values: 1,3,4,6,7,9 I would like to create a set that includes all numbers in the collection between and including 1 and 9, i.e. set = 1-9.
How would I do this?
Edit
I shouldn't say I have a "collection" of integers, rather - I have objects stored in core data and each object has an int64_t attribute associated with it, so I don't have a pointer to an actual collection of the objects, and I want to avoid fetching the objects just to create a collection.
Edit: As it turned out in the discussion, the question was how to create a range
with a given minimal and maximal value. This is done with
NSMakeRange(min, max + 1 - min)
Just use a NSMutableIndexSet and add them one by one with the method addIndex
You could do something like this:
NSArray *array = #[#1,#3,#4,#6,#7,#9];
NSMutableIndexSet *set = [[NSMutableIndexSet alloc] init];
for (NSNumber *value in array) {
[set addIndex:[value integerValue]];
}

Objective-C for Dummies: How do I get a value out of NSDictionary?

so I'm having the most difficult of time pulling values out of an NSDictionary. Right now I just have a dictionary that is populated from a JSON call and it only contains a key named 'Success' with a value of 0 or 1.
How do I do a conditional on that value to check if its 0 or 1? I've tried a bunch of things, but I'm not getting anywhere. Here's my current code:
[[jsonDictionary objectForKey:#"Success"] isEqualToNumber:1]
I'm getting passing argument 1 of 'isEqualToNumber:' makes pointer from integer without a cast' as a warning, and the app crashes when it hits that line anyway.
And a subquestion, what's the difference between objectForKey and valueForKey? Which one should I use by default?
Anyway, this noob in Objective-C would truly appreciate some help on this. Thanks in advance!
Since dictionaries contain Objective-C objects, an entry containing a number is an NSNumber instance. NSNumber provides a convenience method, -intValue, for extracting its underlying int value:
if ([[jsonDictionary objectForKey:#"Success"] intValue] == 1) { … }
Note that NSNumber has other convenience methods for extracting its underlying value as other C data types.
In most cases, you should use -objectForKey: instead of -valueForKey:. The former is the canonical method to obtain an entry in the dictionary and is declared in NSDictionary. The latter is declared in NSObject and is used in Key-Value Coding contexts, where the key must be a valid KVC key, and there’s additional processing — for instance, if you’re using -valueForKey: in a dictionary with a key that starts with #, that character is stripped from the key and [super valueForKey:key] is called.
The number 1 is not an object pointer. Use an NSNumber instance instead if you want to use a number in an NSDictionary.
[[jsonDictionary objectForKey:#"Success"]
isEqualToNumber:[NSNumber numberWithInteger:1]]
[[jsonDictionary objectForKey:#"Success"] isEqualToNumber: [NSNumber numberWithInt:1]]
Number and Value Programming Topics: Using Numbers
NSNumber: What is the point ?
You can get the value of dictionary in different ways like checking
the value first.
Solution 1: Using simple if statement.
int value = 0;
if ([[jsonDictionary objectForKey:#"Success"]intValue]==1){
value = [[jsonDictionary objectForKey:#"Success"]intValue];
}
Solution 2: Using ternary operator
value = ([[jsonDictionary objectForKey:#"Success"]intValue]==1) ? 1:0;

Creating an NSArray initialized with count N, all of the same object

I want to create an NSArray with objects of the same value (say NSNumber all initialized to 1) but the count is based on another variable. There doesn't seem to be a way to do this with any of the intializers for NSArray except for one that deals with C-style array.
Any idea if there is a short way to do this?
This is what I am looking for:
NSArray *array = [[NSArray alloc] initWithObject:[NSNumber numberWithInt:0]
count:anIntVariable];
NSNumber is just one example here, it could essentially be any NSObject.
The tightest code I've been able to write for this is:
id numbers[n];
for (int x = 0; x < n; ++x)
numbers[x] = [NSNumber numberWithInt:0];
id array = [NSArray arrayWithObjects:numbers count:n];
This works because you can create runtime length determined C-arrays with C99 which Xcode uses by default.
If they are all the same value, you could also use memset (though the cast to int is naughty):
id numbers[n];
memset(numbers, (int)[NSNumber numberWithInt:0], n);
id array = [NSArray arrayWithObjects:numbers count:n];
If you know how many objects you need, then this code should work, though I haven't tested it:
id array = [NSArray arrayWithObjects:(id[5]){[NSNumber numberWithInt:0]} count:5];
I can't see any reason why this structure in a non-mutable format would be useful, but I am certain that you have your reasons.
I don't think that you have any choice but to use a NSMutableArray, build it with a for loop, and if it's really important that the result not be mutable, construct a NSArray and use arrayWithArray:
I agree with #mmc, make sure you have a valid reason to have such a structure (instead of just using the same object N times), but I'll assume you do.
There is another way to construct an immutable array which would be slightly faster, but it requires creating a C array of objects and passing it to NSArray's +arrayWithObject:count: method (which returns an autoreleased array, mind you) as follows:
id anObject = [NSNumber numberWithInt:0];
id* buffer = (id*) malloc(sizeof(id) * anIntVariable);
for (int i = 0; i < anIntVariable; i++)
buffer[i] = anObject;
NSArray* array = [NSArray arrayWithObjects:buffer count:anIntVariable];
free(buffer);
You could accomplish the same thing with even trickier pointer math, but the gains are fairly trivial. Comment if you're interested anyway.
Probably the reason there is no such method on NSArray is that the semantics are not well defined. For your case, with an immutable NSNumber, then all the different semantics are equivalent, but imagine if the object you were adding was a mutable object, like NSMutableString for example.
There are three different semantics:
retain — You'd end up with ten pointers to the same mutable string, and changing any one would change all ten.
copy — You'd end up with ten pointers to the same immutable string, or possibly ten different pointers to immeduable strings with the same value, but either way you'd not be able to change any of them.
mutableCopy — You'd end up with ten different mutable string objects, any of which you could change independently.
So Apple could write three variants of the method, or have some sort of parameter to control the semantics, both of which are ugly, so instead they left it to you to write the code. If you want, you can add it as an NSArray category method, just be sure you understand the semantic options and make it clear.
The method:
-(id)initWithArray:(NSArray *)array copyItems:(BOOL)flag
has this same issue.
Quinn's solution using arrayWithObjects:count: is a reasonably good one, probably about the best you can get for the general case. Put it in an NSArray category and that's about as good as it is going to get.