Is it possible to scope enums to a class in Objective-C? - objective-c

I'm new to Objective-C and trying to figure out enums. Is there a way to scope an enum to a class so that the values could be used by another class? Something like this:
#interface ClassA {
typedef enum {
ACCEPTED,
REJECTED
} ClassAStatus;
}
#end
#interface ClassB {
typedef enum {
ACCEPTED,
REJECTED
} ClassBStatus;
}
#end
Though that does not work, obviously. Or is there a better way to do enums altogether?
Edit: I guess my wording wasn't clear, but I'm not asking how to declare enums. I'm aware that putting them at the top of the file works. I'm asking if there's a way to scope them so the values aren't global to the entire file.

You have to prefix your public enums. Simply put the enum definition in the header of your class.
// ClassA.h
typedef enum {
ClassAStatusAccepted,
ClassAStatusRejected
} ClassAStatus;
#interface ClassA {
ClassAStatus status;
}
#end
// ClassB.h
typedef enum {
ClassBStatusAccepted,
ClassBStatusRejected
} ClassBStatus;
#interface ClassB {
ClassBStatus status;
}
#end
This is how Apple does it.
Or you could use the new style:
// UIView.h
typedef NS_ENUM(NSInteger, UIViewAnimationCurve) {
UIViewAnimationCurveEaseInOut, // slow at beginning and end
UIViewAnimationCurveEaseIn, // slow at beginning
UIViewAnimationCurveEaseOut, // slow at end
UIViewAnimationCurveLinear
};

Just put the enum right at the top of your .h, like Apple does in UITableView.h, for example:
//
// UITableView.h
// UIKit
//
// Copyright (c) 2005-2012, Apple Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>
#import <UIKit/UIScrollView.h>
#import <UIKit/UISwipeGestureRecognizer.h>
#import <UIKit/UITableViewCell.h>
#import <UIKit/UIKitDefines.h>
typedef NS_ENUM(NSInteger, UITableViewStyle) {
UITableViewStylePlain, // regular table view
UITableViewStyleGrouped // preferences style table view
};
typedef NS_ENUM(NSInteger, UITableViewScrollPosition) {
UITableViewScrollPositionNone,
UITableViewScrollPositionTop,
UITableViewScrollPositionMiddle,
UITableViewScrollPositionBottom
}; // scroll so row of interest is completely visible at top/center/bottom of view
typedef NS_ENUM(NSInteger, UITableViewRowAnimation) {
UITableViewRowAnimationFade,
UITableViewRowAnimationRight, // slide in from right (or out to right)
UITableViewRowAnimationLeft,
UITableViewRowAnimationTop,
UITableViewRowAnimationBottom,
UITableViewRowAnimationNone, // available in iOS 3.0
UITableViewRowAnimationMiddle, // available in iOS 3.2. attempts to keep cell centered in the space it will/did occupy
UITableViewRowAnimationAutomatic = 100 // available in iOS 5.0. chooses an appropriate animation style for you
};
You probably recognize some of these name, but you may not have been aware they were actually apart of a public enum in Apple's header files.

Just want to add to #DrummerB's answer that I usually write like this. The namespace in camelCase, and then the constant in upper case.
typedef enum {
ClassAStatus_ACCEPTED,
ClassAStatus_REJECTED
} ClassAStatus;

Related

How to find unused ivars in Xcode

Sometimes I declare an ivar but after a while I am no longer using it. I would like to remove this sort of cruft from my code, but I cannot find a warning that will show me my unused ivars.
Is there a tool or built in feature of Xcode that will allow me to find all of my unused ivars?
I see that the static analyzer has CLANG_ANALYZER_OBJC_UNUSED_IVARS, but it does not seem to do anything.
#implementation AppDelegate
{
#private
BOOL _foo; // Never read or written to
}
Runing the analyzer in Xcode 5 with CLANG_ANALYZER_OBJC_UNUSED_IVARS (unused ivars) set to YES never produces a warning.
Based on the relevant Clang source code and a couple of quick tests, it seems that the analyzer does not look at ivars that are not both declared in the #interface and marked #private.
#interface Igloo : NSObject
{
NSString * address; // No warning
#private
NSInteger radius; // Warning
}
#end
#implementation Igloo
{
NSInteger numWindows; // No warning
#private // Has no real effect, of course; just testing
NSString * doormatText; // No warning
}
#end
I suggest filing a bug/submitting a patch.
It appears that the static analyzer option only works if you declare the ivar in the header file.
This generates the analyzer warning correctly:
// AppDelegate.h
#interface AppDelegate : NSObject <UIApplicationDelegate>
{
BOOL _foo; // never read or written
}
#end
Neither of these generates any sort of analyzer warning:
// AppDelegate.m
#interface AppDelegate ()
{
#private
BOOL _goo; // never read or written
}
#end
#implementation AppDelegate
{
#private
BOOL _hoo; // never read or written
}
#end
So it looks like you cannot use the modern syntax to keep ivars in the .m file if you want to check for unused ivars.
In Xcode from product menu click on analyze... It will show you unused variables. This will also tell you about dead code.

Hiding types from Objective-C framework header files

I'm writing a media player framework for a project I'm working on. This depends on VLC. One of my classes' header file looks like this
#import <vlc/vlc.h>
#interface MediaPlayerVLC : MediaPlayer
{
libvlc_media_player_t *player;
libvlc_media_t *media;
}
#end
I need the instance variables in the class, and I need the #import <vlc/vlc.h>, because they're defined in there. But I don't want users of this framework to have to import all of VLC's headers just for these two types. I've seen a few solutions to this problem around...
Forward declaration, such as #class. Unfortunately, these types are typedef struct types, I can't seem to find any way to forward declare them
declare the ivars as void *, then cast them whenever I want to use them. I'd like to avoid this if possible, as we lose type-safety and implementation files become full of ugly casts.
I've seen this in Apple's frameworks...
#interface CAAnimation : NSObject <NSCoding, NSCopying, CAMediaTiming, CAAction>
{
#private
void *_attr;
uint32_t _flags;
}
What does _attr point to? I guess it would be a struct of ivars, I'm curious what advantages this has...
Two header files for the class, one public and one private. The private one would look like the above, and the public would just have void * pointers. This is pretty ugly, as I'd have to be very careful to keep them both in sync.
What's considered best practise? Is there an approach I've missed?
You can use class extensions. You should try doing this:
MediaPlayerVLC.h:
#interface MediaPlayerVLC : MediaPlayer
{
}
#end
MediaPlayerVLC.m:
#import "MediaPlayerVLC.h"
#import <vlc/vlc.h>
#interface MediaPlayerVLC ()
{
libvlc_media_player_t *player;
libvlc_media_t *media;
}
#end
#implementation MediaPlayerVLC
// The implementation
#end
From Apple's docs:
Class extensions are like anonymous categories, except that the
methods they declare must be implemented in the main #implementation
block for the corresponding class.
Using the Clang/LLVM 2.0 compiler,
you can also declare properties and instance variables in a class
extension.
That's using a class extension category to declare extra ivars in the implementation file.
With the newest compiler you can also declare ivars in your class's #implementation section:
// MediaPlayerVLC.m
#import "MediaPlayerVLC.h"
#import <vlc/vlc.h>
#implementation MediaPlayerVLC
{
libvlc_media_player_t *player;
libvlc_media_t *media;
}
...
#end
You can put ivars in implementation like
#implementation Something
{
int a;
}

Using Methods Without Declaring them in the header

Recently I used an opaque pointer type in my code. I did this because I wanted to use c++ code in my obj c project without having to change every single file to .mm.
The way I use the c++ code is that I have a opaque pointer to my c++ code as a member of a .mm file. All the c++ is hidden in the implementation file.
In this class that contains my c++ I have a need to import an existing class "MyClass". I can import it fine in the implementation class but if I try to import it in the header I get c++ errors saying " ISO C++ forbids declaration of 'CARingBufferCPPWrapper' with no type".
I "can" just write the method in the .mm file and omit it from the header but I get a warning say that my .mm file may not respond to the method.
A lot of this is quite new to be so my terminology may be a little off. Let me know if I can clarify my question in any way.
TLDR: How can Class X Safely call a method in Class Y without the method being declared in Class Y header?
//My Header
#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
#define kBufferLength 5120
//#define "Myclass.h"
typedef struct ringbufferobj * RingBufferOBJ;
RingBufferOBJ newRingBufferOBJ();
#interface CARingBufferCPPWrapper : NSObject {
RingBufferOBJ ringbuffer;
NSThread *producerthread;
int duration;
}
#property (nonatomic, retain) NSThread *producerthread;
#property(nonatomic)int duration;
//-(void)myclassfunction(MyClass *)classref
#end
//My Implementation .mm
#import "CARingBufferCPPWrapper.h"
#import "CARingBuffer.h"
#import <AudioToolbox/AudioToolbox.h>
#import "MyClass.h"
struct ringbufferobj
{
CARingBuffer *ringbuffer;
AudioBufferList *inputbuffer;
Float64 firstInputSampleTime;
Float64 firstOutputSampleTime;
Float64 inToOutSampleTimeOffset;
BOOL producerthreadisrunning;
};
RingBufferOBJ newRingBufferOBJ(){
RingBufferOBJ ringbuffer=(RingBufferOBJ)malloc(sizeof(struct ringbufferobj));
return ringbuffer;
}
#implementation CARingBufferCPPWrapper
#synthesize producerthread;
#synthesize duration;
-(void)myclassfunction(MyClass *)classref
{
}
#end
I'm not quite sure what your question is as I couldn't find anything that actually asks anything. (I even Cmd+F'd for "?"). I'm assuming however, that you're asking what you can do to get rid of that warning?
-If a method is declared above the method it is called it, there should be no warning. ( methods are compiled in order). To get rid of such a warning, you'd have to forward declare the method signature. (This is conventionally in the header, but I don't think there's anything stopping you just doing it at the top of your .m)
-(void) methodA {
..do something
[self methodB]; //Warning here because the compiler has not yet seen methodB
}
-(void) method B {
..[self methodA]; //No warning, compiler knows what methodA is at this point.
}

#class for typedef enum?

In one header file, I have something like:
// PasscodeInputViewController.h
typedef enum {
PasscodeInputModeOn, // set passcode
PasscodeInputModeEnter, // enter passcode
PasscodeInputModeChange, // change passcode
PasscodeInputModeOff // turn off passcode
} PasscodeInputMode;
In another header file, I declare a method that takes an argument of type PasscodeInputMode:
#import "PasscodeInputViewController.h"
- (void)presentPasscodeInputWithMode:(PasscodeInputMode)mode;
As you can see, I use #import "PasscodeInputViewController.h" as above so that PasscodeInputMode is recognized, but is there a #class equivalent for typedef enum?
No, there isn’t an equivalent.
Enumerations in Objective-C are the same as enumerations in C. Since the underlying type of an enumeration is implementation-dependent (e.g., it could be char or int), the compiler must know the complete declaration of the enumeration.
That said, a type specifier
enum nameOfEnum
without listing the enumeration members is valid C provided it appears after the type it specifies is complete, i.e., enum nameOfEnum { … } must appear beforehand in the translation unit.
In summary: There’s no forward declaration of enumerations, only backward references.
#Caleb, #Bavarious:
Most recent way (Jan, 2017) to forward declare the enum (NS_ENUM/NS_OPTION) in objective-c is to use the following:
// Forward declaration for XYZCharacterType in other header say XYZCharacter.h
typedef NS_ENUM(NSUInteger, XYZCharacterType);
// Enum declaration header: "XYZEnumType.h"
#ifndef XYZCharacterType_h
#define XYZCharacterType_h
typedef NS_ENUM(NSUInteger, XYZEnumType) {
XYZCharacterTypeNotSet,
XYZCharacterTypeAgent,
XYZCharacterTypeKiller,
};
#endif /* XYZCharacterType_h */`
Similar question Forward-declare enum in Objective-C
Forward declaration of classes is necessary to enable two classes to refer to each other. It's not uncommon to have two classes that are defined in terms of each other:
#class ClassB;
#interface ClassA : NSObject
{
ClassB *objectB;
}
#end
#interface ClassB : NSObject
{
ClassA *objectA;
}
#end
There's no way to make that compile without the forward declaration.
The same is not true of enumerations. enum just creates a set of named values... you can't include one enumeration in the definition of another. Therefore, there's never a need to forward declare an enumeration.
I think what you want is a class that has PasscodeInputMode as a property of it. That way you can be passing around an instantiated object of that class, and can set/get that property, and do other object-like-things with it (assume that's why you'd want to find a "#class equivalent"

Objective-C - define an enum than can be dot called like ENUMTYPE.ENUMVAL

I've read many things about enum types in objective-c, and I see there is many ways to define them. But I don't see the right way (if there is one) to define an enum that can be called with CARS.ROLLSROYCE and that cannot be used only with ROLLSROYCE in the code.
So I can define ROLLSROYCE in the CARS enum and also in the BEAUTIFULCARS enum.
Do you know the way to define such an enum ?
You are trying to implement namespaces for your Enums in Objective-C. What you're asking for is a lot of elbow grease in Objective-C. You are probably best-off using C++ for this, since it is easy and afaik fully supported in any iOS or Cocoa application. You'll have to rename the files that #import your C++ code to .mm files instead of .m files, and the C++ compiler can be trickier than the Objective-C one. Going this route you'll create a header file like Enums.h.
// Enums.h
namespace CARS
{
enum CARS
{
ROLLSROYCE
};
}
namespace BEAUTIFULCARS
{
enum BEAUTIFULCARS
{
ROLLSROYCE = 45
};
}
And in your .mm sourcefile
#import "Enums.h"
-(void)printEnumvals
{
NSLog(#"CARS %d BEAUTIFULCARS %d",
CARS::ROLLSROYCE,
BEAUTIFULCARS::ROLLSROYCE);
}
If you want to avoid using C++ for this solution, there's a lot more elbow grease, bookkeeping, and opportunity for error. You'll need a header and a source file for this.
// CARS.h
#interface BEAUTIFULCARS : NSObject
{
enum
{
BEAUTIFULCARS_ROLLSROYCE = 45
} BEAUTIFULCARS;
}
#end
#interface CARS : NSObject
{
enum
{
CARS_ROLLSROYCE
} CARS;
}
#end
// CARS.m
#implementation BEAUTIFULCARS
+(NSInteger)ROLLSROYCE{ return BEAUTIFULCARS_ROLLSROYCE; }
#end
#implementation CARS
+(NSInteger)ROLLSROYCE{ return CARS_ROLLSROYCE; }
#end
Your .m source is almost the same:
#import "CARS.h"
-(void)printEnumvals
{
NSLog(#"CARS %d BEAUTIFULCARS %d",
CARS.ROLLSROYCE,
BEAUTIFULCARS.ROLLSROYCE);
}
Objective-C does not manage scope in the same way that most other OO languages do. Interfaces define the properties and messages that an object that interface supports, but don't support protection levels like public or private. When you define an enum in an #interface, that enum ends up in global scope.
For my case, I didn't want to use C++ namespaces or write redundant Objective-C classes for such a simple case, so I fallen back to the C.
// Enum.h
typedef struct
{
const int ROLLSROYCE;
} _CARS;
typedef struct
{
const int ROLLSROYCE;
} _BEAUTIFULCARS;
extern const _CARS CARS;
extern const _BEAUTIFULCARS BEAUTIFULCARS;
And then in Enum.m, define values
// Enum.m
#import "Enum.h"
const _CARS CARS = {0};// 0 is to be assigned to ROLLSROYCE field in struct
const _BEAUTIFULCARS BEAUTIFULCARS = {1}; // same but with 1
And finally, in your "main" code
#import "Enum.h"
// Some method
{
NSLog(#"I can refer to CARS.ROLLSROYCE = %d and BEAUTIFULCARS.ROLLSROYCE = %d", CARS.ROLLSROYCE, BEAUTIFULCARS.ROLLSROYCE);
}
Which will produce this output:
I can refer to CARS.ROLLSROYCE = 0 and BEAUTIFULCARS.ROLLSROYCE = 1