Where to create and how to use Enum in iOS? - ios

I have started learning iOS development.
I want to use enum in my sample project.
I've declared enum in sample.h like following. I hope I've declared this correctly.
typedef enum{s=1,m,t,w,th,f,sa} days;
I want to use this in viewController.m. In viewController.h, I've imported sample.h.
I want to use enum with the name like "days.sa". But more code i searched in google, they've said like create a instance variable in "sample.h" like
#interface Sample:NSObject
{
days d;
}
If I want to use this means, I need to create and use instance. But I don't want like that.
I need to use like
days.d or days.sa or days.th
How to do that ?, This must be used for the whole Project and
How to create enum as class variable instead of instance variable ?

In the enum you've created, s, m etc. are now available globally (i.e. to anything that imports sample.h). If you want the integer corresponding to Saturday, for example, it's just sa, not days.sa. I think you're confusing enums with structures.
For this reason, it's better to use more verbose names in your enum. Something like:
typedef enum
{
WeekdaySunday = 1,
WeekdayMonday,
WeekdayTuesday,
WeekdayWednesday,
WeekdayThursday,
WeekdayFriday,
WeekdaySaturday
} Weekday;
so e.g. WeekdayMonday is now just another way of writing 2 in your app, but will make your code more readable and pre-defines the possible legal values for a variable of type Weekday.
The above is fine, but for better compiler support and to ensure the size of a Weekday, I'd recommend using NS_ENUM:
typedef NS_ENUM(NSInteger, Weekday)
{
WeekdaySunday = 1,
WeekdayMonday,
WeekdayTuesday,
WeekdayWednesday,
WeekdayThursday,
WeekdayFriday,
WeekdaySaturday
};

hey you use enum like this here is an example
In .h define enum
typedef enum{s=1,m,t,w,th,f,sa} days;
In .m play with enum element like this
days d1 =f;
switch (d1) {
case m:
case t:
NSLog(#"You like Tuesday");
break;
case w:
case th:
break;
case f:
NSLog(#"You like friday");
break;
case sa:
NSLog(#"You satureday");
break;
case s:
NSLog(#"You like sunday");
break;
default:
break;
}
if you want learn more click this.

#import <Foundation/Foundation.h>
typedef enum{
s=1,m,t,w,th,f,sa
} days;
#interface weekday : NSObject
#property (nonatomic, assign) days day;
#end
#implementation weekday
#end
int main(int argc, const char * argv[])
{
#autoreleasepool {
weekday *sunDay=[[weekday alloc]init];
sunDay.day=s;
NSLog(#"Today is %d",sunDay.day);
}
return 0;
}

Creating Enum in Enumrations.h
typedef enum
{
Atype = 1,
Btype,
Ctype,
Dtype,
Etype,
}type;
Where ever you want to user this enum just import Enumrations.h, and you can use Atype without creating type object.
you can simply use NSLog(#"%#",#(Atype)).

Related

#import "Project-Swift.h" comes some strange issue

Project is mixed with oc and swift.
#import "myProjectName-Swift.h" in the AppDelegate.m,:
Project is Objective-c language created by me, and using almost swift language to write. and In the Appdelegate.m I want to use swift's class, and so
But unfortunate, my project occurs some error in myProjectName-Swift.h:
The code is below:
SWIFT_CLASS_PROPERTY(#property (nonatomic, class, readonly, copy)
NSString * _Nonnull ;)
+ (NSString * _Nonnull);
SWIFT_CLASS_PROPERTY(#property (nonatomic, class, readonly, copy)
NSString * _Nonnull ;)
+ (NSString * _Nonnull);
SWIFT_CLASS_PROPERTY(#property (nonatomic, class, readonly, strong) UIColor * _Nonnull APP_COLOR;)
+ (UIColor * _Nonnull)APP_COLOR;
The error are:
Expected ';' at end of declaration list.
cannot declare variable inside #interface or #protocal
Expected member name or ';' after declaration specifiers
Expected ']'
Property requires fields to be named
Missing '[' at start of message send expression
And so on...
Attension
And In the global swift, I set Chinese characters variable like this:
class Global: NSObject {
}
EDIT - 1
Because I think a error point out the static let "'s ,so I annotation this line, project will not show this error. Or I delete the ,`, will not show the error too.
Objective-C doesn't support Unicode in identifiers (variable names, class names, method names etc), only in string literals ("🏋"). Only a subset of ASCII is allowed (start with _[a-zA-Z], +[0-9] afterwards).
Example:
class MyClass : NSObject {
func 😞() { }
}
This will break when you compile it in a mixed project. Instead you need to give it a valid Objective-C name, like so:
class MyClass : NSObject {
#objc(unhappyFace)
func 😞() { }
}
which will compile (and you need to access it as unhappyFace on the ObjC side).
Or in your example you need to modify your Global object:
class Global: NSObject {
#objc(emptyNumberNotAllowed)
static let 手机号码不能为空 = "手机号码不能为空"
... etc ...
}

Create enum values default to NSInteger

I understand that when we declare enum like the ones below, the values are default to type "int"
enum{
category0,
category1
};
However, I am getting issues now that iOS supports 64-bit. The solution I am thinking to prevent changing a lot in my code is to make this enum values default to "NSInteger" instead of "int". On my understanding, the system will decide whether NSInteger will be of type int or long depending if it's running on 32 or 64 bit.
I am having difficulty understanding enum so I will appreciate your help on this.
Thanks
If I use typedef as suggested by the comments:
typedef NS_ENUM(NSInteger, Category){
category0,
category1
}
how should i use it? Normally when I compare it with, say, tableview's indexpath.section, i do this
if(indexpath.section == category0){
...
}
if I declare that "Category", do I need to use it? Sorry I don't quite understand typedef.
Try
typedef enum{
category0,
category1
} Category;
or
typedef NS_ENUM(NSInteger, Category) {
category0,
category1
};
You also can explicitly set integer numbers to your enums values
typedef NS_ENUM(NSInteger, Category) {
category0 = 0,
category1 = 1,
category42 = 42
};
Then you can use them the same as int
if(indexpath.section == category0){
...
}

How do you return a struct like CLLocationCoordinate2D from a class method properly?

This question uses CLLocationCoordinate2D as an example, but this applies to other structs as well, such as CGPoint (although ones like those are usually automatically included).
I want to use CLLocationCoordinate2D as a return value in a class method. If it were an object you could write the following at the top and it would be fine, as long as the .m file had a reference to CoreLocation.h
#class ClassName
Is there an equivalent way of telling the compiler not to worry about the struct without re-declaring it or importing the header file into the class' header file?
I do not want to import CoreLocation.h into the header file, since that would mean every file that imports that header file would inherit CoreLocation.
Thanks
I'm not totally getting the point why you do not want to import CoreLocation, but CLLocationCoordinate2D is declared in CoreLocation.h. I'm not aware about a method like #class for struct and I don't think it exists since struct are C types.
What you can do is create your own class that wraps the CLLocationCoordinate2D or return the NSValue from it, or (why not?) a dictionary.
Easiest way to do this is to just use an object instead of the struct, then you can use the #class keyword. In this case, the CLLocation object works just fine. Alternatively you can often use an NSDictionary in place of a struct, but an object is a bit easier to manage.
You return a struct like any other type. But you should be aware that when returning a struct you are returning a copy of the internal value on the stack as a temporary variable. Unlike an Objective-C object where you are actually returning a pointer.
The type you return MUST be a complete type. That means, in your method declaration you need the definition of the struct. In your case, that means, you need to include the header.
For example:
typedef struct MyStruct {
int a;
int b;
} MyStruct;
#interface MyClass : NSObject
+(MyStruct) theStruct;
#end
#implementation MyClass
+(MyStruct) theStruct {
MyStruct s = {.a = 1, .b = 2};
return s;
}
#end
int main(int argc, const char * argv[])
{
#autoreleasepool {
MyStruct s1 = [MyClass theStruct];
s1.a = 100;
s1.b = 100;
NSLog(#"s1 = {%d, %d}", s1.a, s1.b);
NSLog(#"MyStruct.theStruct = {%d, %d}", [MyClass theStruct].a, [MyClass theStruct].b);
[MyClass theStruct].a = 0; // has no effect!
}
return 0;
}
Prints:
s1 = {100, 100}
MyStruct.theStruct = {1, 2}
There is no straightforward way of doing that with single keyword.
Here you can find why it is not straightforward, although it is stated that it is not possible to do that, somewhat true but not completely.
Forward declare a struct in Objective-C
And here is the workaround of doing this
Forward declare structs in Objective C
Hope this will help.

Bitmasking in Objective C

I'd like to learn bit masking. As far as I understand, it is means to store binary values of certain type into one variable.
If the above assumption is true, I figured I could do something like this:
typedef NSUInteger Traits;
enum
{
TraitsCharacterHonest = 0,
TraitsCharacterOptimistic = 1,
TraitsCharacterPolite = 4,
TraitsCharacterDevious = 8,
TraitsPhysicalTall = 16,
TraitsPhysicalBeautiful = 32,
TraitsPhysicalFat = 64,
TraitsPhysicalBigEyes = 128,
TraitsPhysicalRedHair = 256,
};
#import <Foundation/Foundation.h>
#interface Person : NSObject
#property (strong, nonatomic) NSString *name;
#property (assign, nonatomic) Traits *traits;
#end
Question 1 is, how do I assign more traits to one person?
Question 2 is, do I have to put ever increasing numbers to enum items, or is there a way to indicate this?
Ultimately I want to achieve something like this:
Person *john = [[Person alloc] init];
//here code that assigns john three traits: TraitsCharacterHonest,
//TraitsCharacterOptimistic and TraitsPhysicalBeautiful.
If I understand it correctly, the value of
john.traits should be 100011., reading from right and each place representing that particular enum value / trait..and 0 meaning not having it and 1 meaning having it.
Can you please advice on syntax and explain a particular aspect if needed?
I'd recommend changing a few things:
The enum values can be changed to be a one left-shifted. Makes it a little easier to write, in my opinion.
You don't need to typedef to NSUInteger, you can declare a enum type directly using typedef enum.
And, as other people have mentioned, your property shouldn't be a pointer to a Traits type.
My code would look like this:
typedef enum
{
TraitsCharacterHonest = 1 << 0,
TraitsCharacterOptimistic = 1 << 1,
TraitsCharacterPolite = 1 << 2,
TraitsCharacterDevious = 1 << 3,
TraitsPhysicalTall = 1 << 4,
TraitsPhysicalBeautiful = 1 << 5,
TraitsPhysicalFat = 1 << 6,
TraitsPhysicalBigEyes = 1 << 7,
TraitsPhysicalRedHair = 1 << 8
} Traits;
#import <Foundation/Foundation.h>
#interface Person : NSObject
#property (strong, nonatomic) NSString *name;
#property (assign, nonatomic) Traits traits;
#end
Setting John's traits will look like this:
Person *john = [[Person alloc] init];
john.traits = TraitsCharacterHonest | TraitsCharacterOptimistic | TraitsPhysicalBeautiful;
However, while bit-fields are useful to learn, but they're a real pain to debug. If you want to go and print
this character's traits now, you'll have to write code like this:
NSMutableString *result = [NSMutableString string];
if (self.traits & TraitsCharacterHonest)
{
[result appendString: #"Honest, "];
}
if (self.traits & TraitsCharacterOptimistic)
{
[result appendString: #"Optimistic, "];
}
if (self.traits & TraitsCharacterPolite)
{
[result appendString: #"Polite, "];
}
// etc...
Additionally, syntax for operations like removing a trait are confusing. You'll have to use & and a NOT-ed constant,
// remove 'Tall' trait
john.traits = john.traits & ~TraitsPhysicalTall
If you can (and performance isn't too much of a issue), I'd prefer using a higher-level feature. Perhaps an NSSet with string constants? e.g.
__unused static NSString *TraitsCharacterHonest = #"TraitsCharacterHonest";
__unused static NSString *TraitsCharacterOptimistic = #"TraitsCharacterOptimistic";
__unused static NSString *TraitsCharacterPolite = #"TraitsCharacterPolite";
// etc...
#interface Person : NSObject
#property (strong, nonatomic) NSString *name;
#property (assign, nonatomic) NSMutableSet *traits;
#end
Then you can do:
// adding
[john.traits addObject: TraitsCharacterHonest];
// checking
[john.traits containsObject: TraitsCharacterHonest];
// removing
[john.traits removeObject: TraitsCharacterHonest];
Makes more sense to me. What's more, you can print the description of the traits directly with
NSLog(#"John's traits: %#", john.traits);
and you'll get reasonable output.
One issue that you can run into is that using bit masks to indicate membership within sets can be capped by the number of bits in the underlying data type. For instance an unsigned long of 32 bits has room only for 32 disjoint or different members. If you need to add a 33rd, you are out of luck unless you go to a 64 bit unsigned integer.
One workaround for this is to use an array of bytes. With this approach you have to specify your bit membership as two pieces of data, the offset to the byte and the bit mask to use for the specific bit.
I have also seen people use byte arrays for single membership so that rather than one bit used, the entire byte is used. It can be a waste of memory but then it may be that it is more flexible and useful and the amount of memory wasted is not a problem.
For using an array of bytes to hold the set of bits, you might consider using an unsigned long to represent the members of the set in which the least significant byte is the bit mask and the rest of the bytes are used as an unsigned 3 byte offset into the byte array. You would then do something like the following:
int getBitSet (unsigned char *bArray, unsigned long ulItem)
{
unsigned long ulByteOffset = ((ulItem >> 8) & 0x00ffffff);
unsigned char ucByteMask = (ulItem & 0x000000ff);
return (*(bArray + ulByteOffset) & ucByteMask);
}
int setBitSet (unsigned char *bArray, unsigned long ulItem, unsigned long ulNewValue)
{
unsigned char oldValue;
unsigned long ulByteOffset = ((ulItem >> 8) & 0x00ffffff);
unsigned char ucByteMask = (ulItem & 0x000000ff);
oldValue = *(bArray + ulByteOffset) & ucByteMask;
if (ulNewValue) {
*(bArray + ulByteOffset) |= ucByteMask; // set bit
} else {
*(bArray + ulByteOffset) &= ~ucByteMask; // clear bit
}
return oldValue;
}
You could then have a set of functions to get and set the bytes or you could use macros. With C++ you can create your own class for this functionality and provide various types of logical operations as well so that you can create sets of various kinds and then perform logical operations on the sets.
In iOS 6 or above, Mac OS X 10.8 and above
You can do:
typedef NS_OPTIONS(NSUInteger, Traits) {
TraitsCharacterHonest,
TraitsCharacterOptimistic,
TraitsCharacterPolite,
TraitsCharacterDevious,
TraitsPhysicalTall,
TraitsPhysicalBeautiful,
TraitsPhysicalFat,
TraitsPhysicalBigEyes,
TraitsPhysicalRedHair
};
For more info, refer to http://nshipster.com/ns_enum-ns_options/
Your major issue here is making traits a pointer. Drop the pointer, and do it like you would in C:
john.traits |= TraitsCharacterOptimistic | TraitsCharacterOptimistic | TraitsCharacterOptimistic;
Remember that you only need pointers in a couple of situations in Objective-C:
When you are dealing with actual objects (derived from NSObject)
When you need to pass a primitive by reference (an int * argument to a function to return count), in which case you take the adress of a local variable, and that pointer is not saved by the function.
When you need an array of primitive types, dynamically allocated on the heap (e.g. using malloc & friends).
Otherwise, just use a stack-allocated primitive type, as you can do a lot of things with it.
First of all change:
...
typedef NSUInteger Traits;
enum
{
TraitsCharacterHonest = 0, //cann't be a 0
...
};
...
#property (assign, nonatomic) Traits *traits; //you no need create a pointer to a primitive type
to:
...
typedef NSUInteger Traits;
enum
{
TraitsCharacterHonest = 1,
...
};
...
#property (assign, nonatomic) Traits traits;
For assigning you should do follow:
john.traits |= TraitsCharacterHonest | TraitsCharacterDevious;
Bitwise operations in ObjC are the same like as in C language.
Check this tutorial Bitwise Operators in C and C++: A Tutorial
Assuming:
1 << 8 is the same what 100000000:
john.traits = TraitsCharacterHonest | TraitsCharacterOptimistic | TraitsPhysicalBeautiful;
is exactly the same as:
john.traits = 000000001 | 000000010 | 000100000;
and the result is:
john.traits = 000100011
Now, when you want to check conditional:
if (self.traits & TraitsCharacterHonest) { ... }
it is equivalent to:
if (000100011 & 000000001) { ... }
and result of that is:
if (000000001) { ... }
And, this is actually 1, not zero value is true, so the whole conditional is true. Enjoy:-)

Enum, PList or some other storage?

iOS 5.0 SDK
I have a method that took a parameter as a 'type' that I defined. Lets call it 'Places'. This type was defined as the following:
typedef enum {
kBar = 0,
kRestaurant = 1,
kCafe = 2
} Places
My method would take a parameter of Places.
Based on the Place type passed in, I would append the type to the url:
ex: http://www.domain.com/place=1
However, the url parameter cannot be a number it has to be a string.
ex: http://www.domain.com/place=restaurant
I know enums cannot be strings so I am trying to figure out the right approach for this. Do I have a plist and then read the plist into a dictionary? Is there another way?
I would do something like:
typedef enum {
PlaceTypeBar = 0,
PlaceTypeRestaurant = 1,
PlaceTypeCafe = 2
} PlaceType
#interface PlaceTypeHelper : NSObject
+ (NSString *) stringForPlace:(PlaceType)place;
#end
#implementation
+ (NSString *) stringForPlace:(PlaceType)place {
NSArray *places = [NSArray arrayWithobjects:#"Bar", #"Restaurant", #"Cafe", nil];
return [places objectForKey:(NSInteger)place];
}
#end
Headups, I've no tested the code yet.
There's a lot of different approaches you could take. Here's what I might do myself.
Assuming there's a finite and known amount of values, you can do a simple function which returns the string for the given type :
(NSString*) StringForPlaceType(PlaceType thePlace) {
switch(thePlace) {
case kBar:
return #"Bar";
case kRestaurant:
return #"Restaurant";
case kCafe:
return #"Cafe";
default:
// ...
}
}
No need for an object or class unless you want for flexibility such as dynamic values and such.

Resources