I'm working on an application and my problem started when i tried to encode a model that has an enum property using NSCoding. So i had the idea to convert it to the rawValue and the way back. I looked around a bit and came around the macro NS_ENUM, so my code looks like this:
typedef NS_ENUM(NSInteger, SectionType) {
SectionTypeText = 0,
SectionTypeVideo = 1,
SectionTypeLink = 2,
SectionTypeFile = 3,
SectionTypeQuiz = 4,
SectionTypeAudio = 5,
SectionTypeGame = 6,
SectionTypeHomework = 7
};
But i could find no possible way to convert these to the associated value and the way back. How could i do it? There is a better approach than the NS_ENUM macro?
My Objective-C is a bit rusty, but I think I would just cast it:
SectionType type = (SectionType) 2;
Back works the same:
int typeNumber = type;
Related
I wish to have two different enums, but they might have the same literal; for example:
typedef enum {ONE,TWO,THREE,FOUR,FIVE,SIX} NumbersEnum;
typedef enum {ONE,TWO,THREE,FIVE,EIGHT} FibonacciEnum;
This will raise a compile error because ONE, TWO, THREE, FIVE are repeated in both enums.
Is there a way to make this work as-is (not changing the literals' names or adding a prefix or suffix)?
Is there any way my code using the literals can look like this: int num = NumbersEnum.SIX; and not like this int num = SIX;?
No. That's part of the C and Objective-C language from the beginning of time. You're not going to change it, and nobody is going to change it for you.
You cannot do this with enums; their members are global and the names must be unique. There is, however, a neat technique you can use to make pseudo-namespaces for constants with structs.
Declare your "namespace" in the appropriate header:
extern const struct _FibonacciNumbers
{
int one;
int two;
int three;
int five;
} FibonacciNumbers;
Then initialize the values in an implementation file:
const struct _FibonacciNumbers FibonacciNumbers = {
.one = 1,
.two = 2,
.three = 3,
.five = 5
};
You now access a constant as, e.g., FibonacciNumbers.one, and other struct types can use the same names since the names are private to each of them.
So that's "No" for your first option, but "Yes" to the second.
There is a global enum defined in Objective-C:
typedef enum {
UMSocialSnsTypeNone = 0,
UMSocialSnsTypeQzone = 10,
UMSocialSnsTypeSina = 11, //sina weibo
} UMSocialSnsType;
This code sets the sharetype of a platform:
snsPlatform.shareToType = UMSocialSnsTypeDouban;
In Swift, I want to get the sharetype of the platform:
var snstype = snsPlatform!.shareToType
println(snstype)
Result: UMSocialSnsType (has 1 child)
snstype.toRaw()
Error: UMSocialSnsType does not have a member named "toRaw"
From what I can tell, UMSocialSNSType was declared in Objective-C without using the NS_ENUM macro, so it wasn't imported as a Swift enum. That means that instead of being able to use .toRaw() or UMSocialSNSType.Douban you have to use the different enumeration values as constant structs. Unfortunately the type also doesn't have the appropriate operators (== or ~=) set up, so you have to compare the value property.
var snstype = snsPlatform!.shareToType
switch snstype.value {
case UMSocialSnsTypeDouban.value:
println("douban")
case UMSocialSnsTypeEmail.value:
println("email")
default:
println("other")
}
if snstype.value == UMSocialSnsTypeDouban.value {
println("douban")
}
The good news is that it looks like all the constants autocomplete in Xcode, so you should be able to do find the comparisons you need to do that way.
It looks like the Swift-version of the bridged typedef...enum must be something like:
struct UMSocialSnsType {
var value:Int
init(_ val:Int) {
value = val
}
}
let UMSocialSnsTypeNone = UMSocialSnsType(0)
let UMSocialSnsTypeQzone = UMSocialSnsType(10)
let UMSocialSnsTypeSina = UMSocialSnsType(11)
// etc
Whereas if it had been declared in Objective-C with the NS_ENUM macro, it would look like:
enum UMSocialSnsType: Int {
case UMSocialSnsTypeNone = 0
case UMSocialSnsTypeQzone = 10, UMSocialSnsTypeSina // etc.
}
Currently the only way I know how to do input in D is with the scanf() function. But god damn it's ugly. You would think that since it's an upgrade from C that they would have fixed that.
I'm looking for a way to do it with a single argument. Currently you have to do:
int foo = 0;
scanf("%i", &foo);
writeln("%i", foo);
But it would look a lot cleaner with a single argument. Something like:
int foo = 0;
scanf(foo);
writeln(foo);
Thanks.
readf("%d", &foo); allows working with std.stdio.File rather than C FILE*
foo = readln().strip().to!int();
For reading entire files with lines formatted in the same way:
int[] numbers = slurp!int("filename", "%d");
There's a really cool user-input module here:
https://github.com/Abscissa/scriptlike/blob/master/src/scriptlike/interact.d
Example code:
if (userInput!bool("Do you want to continue?"))
{
auto outputFolder = pathLocation("Where you do want to place the output?");
auto color = menu!string("What color would you like to use?", ["Blue", "Green"]);
}
auto num = require!(int, "a > 0 && a <= 10")("Enter a number from 1 to 10");
The above answers are great. I just want to add my 2 cents.
I often have the following simple function lying around:
T read(T)()
{
T obj;
readf(" %s", &obj);
return obj;
}
It's generic and pretty handy - it swallows any white space and reads any type you ask. You can use it like this:
auto number = read!int;
auto floating_number = read!float;
// etc.
I'm trying to pass a two-dimensional array, which size can be dynamic, as a method argument.
Within the method I'd like to use the array with the general array syntax.
int item = array[row][column];
To pass the array is not possible, so I thought about to use a pointer pointer.
- (void)doSomethingWithArray:(int **)array columns:(int)nColumns rows:(int)nRows
{
int item = array[n][m];
}
But I get the problem when I try to pass the array as the parameter
int array[numberOfRows][numberOfColumns];
[someObject doSomethingWithArray:array columns:numberOfColumns rows:numberOfRows];
I found a lot of tips & tricks, but somehow nothing really works in the way I would like to use it.
Thanks for help,
Eny
Is objective-c based on C99?
If it is, you can use the "new" syntax that allows you to pass dimension information directly.
#include <stdio.h>
void foo(int rows, int cols, int arr[rows][cols]) {
printf("%d, %d\n", arr[0][0], arr[1][4]);
}
int main(void) {
int arr[2][12] = {{1, 2, 3, 4, 5}, {11, 12, 13, 14, 15}};
foo(2, 12, arr);
}
You can see the code running on ideone.
- (void)doSomethingWithArray:(void *)array columns:(int)nColumns rows:(int)nRows {}
...
[someObject doSomethingWithArray:&array columns:numberOfColumns rows:numberOfRows];
enum {
ValidationLoginFailed=2000,
ValidationSessionTokenExpired=2001,
ValidationSessionTokenInvalid=2002,
ValidationEmailNotFound=2003
ValidationSucccesMIN=ValidationLoginFailed,
ValidationSucccesMAX=ValidationEmailNotFound,
ValdationValidSuccessCode=9999,
ValdationInvalidCode=10000
};
typedef int ValidationStatusCodes;
please help me out.
In your code, ValidationStatusCodes means int, not your anonymous enum type. So they aren't actually connected in any way.
However, since your enum contains int values, you could say that there's some sort of relation. You can pass the names of the enumerated values and they will be considered of the int or ValidationStatusCodes type.
By the way, Apple does something similar to what you do, except they typedef their collective names to NSInteger or NSUInteger instead of int or uint. See this question for an example.
With all that said, a more common practice is to typedef your custom type name directly to the anonymous enum, like this:
typedef enum {
ValidationLoginFailed = 2000,
ValidationSessionTokenExpired = 2001,
ValidationSessionTokenInvalid = 2002,
ValidationEmailNotFound = 2003
ValidationSuccessMIN = ValidationLoginFailed,
ValidationSuccessMAX = ValidationEmailNotFound,
ValdationValidSuccessCode = 9999,
ValdationInvalidCode = 10000
} ValidationStatusCodes;