Declaration of #class equivalent for a struct - objective-c

I would like to avoid importing AVFoundation framework in my header but I need to declare CMTime.
For NSObject I can do #class AVPlayer; and import everything in the .m file. How to do this with a struct like CMTime?

If you need to reference CMTime struct in the header, you need to include <CMTime.h>: forward-declaring a struct lets you use the name of the type in declarations of pointers, but not in declarations of members of that struct type.
In other words, you can do this:
struct CMTime; // Forward declaration of the struct
#interface MyInterface : NSObject
-(void)fillCmTime:(CMTime*)buffer;
#end
but you cannot do this:
struct CMTime; // Forward declaration of the struct
#interface MyInterface : NSObject {
// This is not allowed
CMTime time;
}
// This is not allowed either
-(CMTime)getTime;
#end
The reason that you can do #class AVPlayer and then use it in declarations of members is that Objective-C classes (id-types) are implemented as pointers. In fact, you cannot declare variables of an id-type without an asterisk.

Related

Private Enum Declaration

In an Objective-C class I have a #private ivar that uses an enum of the form:
typedef NS_ENUM(NSInteger, PlayerStateType) {
PlayerStateOff,
PlayerStatePlaying,
PlayerStatePaused
};
However, I include this definition in the header file of that class (since it's used in it). This effectively makes the type public, which isn't what I intended. How can I make this enum type private?
Adding my comment as an answer.
You can add this in your .m class so that while importing it is not shared with other classes. You can just add it below your import statements. If the params of this type are used only in this .m class, you can declare that also in this .m file.
Your .m class will look like,
typedef NS_ENUM(NSInteger, PlayerStateType) {
PlayerStateOff,
PlayerStatePlaying,
PlayerStatePaused
};
#interface ViewController () //Use an extension like this in .m class
#property (nonatomic) PlayerStateType param;
#end
Define it in .m file & declare your privare ivar in controller category in .m file. To know about controller category take a look at Difference between #interface definition in .h and .m file.

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;
}

Is it possible to create a #property for an anonymous struct in Objective-C?

I have an anonymous struct in my code that I'd like to access via an assign #property (no pointer). However, since this is an anonymous structure. Here's the cocoa code I created (even if it's cocoa code, it's relevant to objective-c in general.)
#interface ProfileViewController : UIViewController {
struct {
BOOL isDeviceOwner:1;
} _statusFlags;
}
Now I'd like to create a property for _statusFlags:
#property (nonatomic, assign)
Yes, you just define it inline where you would define the type.
#property (nonatomic, assign) struct { ... } statusFlags;
Then when you synthesize it you can do #synthesize statusFlags = _statusFlags if you really like the underscored ivars, but this will generate the ivar for you. You do not need to define it explicitly.
You can also do it by making the property or method take a pointer to a struck, you then only have to let the compiler know that the struct exists but not what is in the struct i.e. the size, for example
struct myPrivateStruct;
...
#property(assign,nonatomic) struct myPrivateStruct * myStructProperty;
the struct myPrivateStruct then has to be then defined in your implementation file and property implement the property manually for example
struct myPrivateStruct { int a, b; float c; };
- (void)setMyStructProperty:(struct myPrivateStruct *)aValue
{
memcpy(&myIVar,aValue,sizeof(struct myPrivateStruct));
}
this is vary similar to us #class in interface files, of Objective-C class.

#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"

Error declaring typedef in header

I created an empty class derived from NSObject:
typedef struct {
NSInteger x;
NSInteger y;
NSInteger z;
}myType;
#interface MyData : NSObject {
}
In the .m file:
#implementation MyData
I get the warning:
No type or storage class may be specified here before 'implementation'
How can I make the typedef work correctly and also make it accessible to other classes that import the "MyData.h" header file?
Do you have #end at the end of interface file? This is one of the possible reasons of this error.
There's something important that you're not showing us, because this is perfectly proper code. If this is in fact your whole .h file, then I'm willing to bet that you're missing the #end needed to close your #implementation declaration.