Using Methods Without Declaring them in the header - objective-c

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

Related

Swift class using Objective-C class using Swift class

I have an obj-c project to which I successfully added a new Swift class A, which is being used by some existing obj-c class B - the use of the automatically generated "MyProject-Swift.h" header worked as expected.
I also successfully added a new Swift class C that uses some existing obj-c class D - the use of the bridging header also worked as expected.
However, suppose I want to refer from my Swift class C to the existing obj-c class B (which in turn refers to the new Swift class A). In order to do that I need to import "B.h" to the bridging header. However, if I do that I get an error in class B: "'MyProject-Swift.h' file not found" (i.e., the file is no longer generated).
Am I doing something wrong or is this a kind of interaction between Swift and Objective-C that is not allowed? It looks like there is a kind of circular reference that the compiler is unable to solve.
--- EDIT ---
I'll try to make the question clearer by adding some code.
-- PREAMBLE --
I added a new Swift class to an obj-c project:
// SwiftClassA.swift
import Foundation
#objc class SwiftClassA : NSObject {
var myProperty = 0
}
The code compiles correctly and is translated into obj-c stubs in the automatically generated "MyProject-Swift.h" header like so:
// MyProject-Swift.h
...
SWIFT_CLASS("_TtC7MyProject11SwiftClassA")
#interface SwiftClassA : NSObject
#property (nonatomic) NSInteger myProperty;
- (instancetype)init OBJC_DESIGNATED_INITIALIZER;
#end
Now, one obj-c class uses SwiftClassA:
// ObjCClass.h
#import <Foundation/Foundation.h>
#import <MyProject-Swift.h>
#interface ObjCClass : NSObject
#property (nonatomic, strong) SwiftClassA *aProperty;
#property (nonatomic) int *aNumber;
#end
This also works seamlessly.
-- THE QUESTION --
Can I now create a new Swift class that refers to the obj-c class (ObjCClass) that is using the Swift class SwiftClassA?
This is what I can't do.
If I add the new Swift class:
// SwiftClassB.swift
import Foundation
#objc class SwiftClassB : NSObject {
var aPropertyOfClassB = 1
func someFunc() {
var objCObject = ObjCClass()
var theProperty = objCObject.aProperty
print("The property is \(theProperty)")
}
}
this of course won't compile because of "Use of unresolved identifier 'ObjCClass'". So I need to add that to the bridging header file:
// BridgingHeader.h
#ifndef MyProject_BridgingHeader_h
#define MyProject_BridgingHeader_h
...
#import "ObjCClass.h"
#endif
However, if I do that, the ObjCClass.h file won't compile giving a "'MyProject-Swift.h' file not found".
I've read in several places (with no example, though) that this may mean that there is a circular reference and that a forward reference using #class could solve the problem. However, I'm not sure what needs to be forward referenced and where, and all my attempts failed.
I hope the question is no longer confusing now!
This is a typical cyclical referencing problem.
Be careful to read the docs:
To avoid cyclical references, don’t import Swift into an Objective-C header file. Instead, you can forward declare a Swift class to use it in an Objective-C header. Note that you cannot subclass a Swift class in Objective-C.
So, you should use "forward declare" in .h, and #import in .m:
// ObjCClass.h
#import <Foundation/Foundation.h>
#class SwiftClassA;
#interface ObjCClass : NSObject
#property (nonatomic, strong) SwiftClassA *aProperty;
#property (nonatomic) int *aNumber;
#end
// ObjCClass.m
#import "ObjCClass.h"
#import "MyProject-Swift.h"
#implementation ObjCClass
// your code
#end

Accessing interface method defined in .m file

MyClass.h file
#import <Foundation/Foundation.h>
#interface MyClass : NSObject
{
// This is the Place of Instance Variable
}
- (void)thePublicMethod;
#end
MyClass.m file
#import "MyClass.h"
#interface MyClass()
- (void)thePrivateMethod;
#end
#implementation MyClass
-(void)thePublicMethod {
NSLog(#"Public Method Called");
}
- (void)thePrivateMethod {
NSLog(#"Private Method Called");
}
#end
The main.m file
#import <Foundation/Foundation.h>
#import "MyClass.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
MyClass *myObj = [[MyClass alloc] init];
[myObj thePublicMethod];
// [myObj thePrivateMethod];
}
return 0;
}
since “Private” methods can be created by defining them in a class’s implementation file while omitting them from its interface file.
i want to access thePrivateMethod from main.m and also can i call thePrivateMethod() from thePublicMethod() is it possible and how ?
If you want to access an internal method from somewhere other than the class's implementation, then you need to truly declare it as a private method.
Move that class extension to its own header file, say MyClass_Private.h. Then #import that header into both main.m and MyClass.m.
I.e. move this:
#interface MyClass()
- (void)thePrivateMethod;
#end
Into a file called MyClass_Private.h and then #import "MyClass_Private.h" in both your MyClass.m and main.m files.
Internal means only used in the innards of this framework or class.
Private means may be used by this framework or the class, but may be exposed to clients that are more intimately tied to the class than through Public API. Typically reserved for framework authors on large scale systems (like the OS).
Public means may be used anywhere by any client of the class.
No matter how or where or IF you declare a method, at all.. If it exists.. calling it is as simple as
[myInstance performSelector:NSSelectorFromString(#"yourSuperSecretMethod:")
withObject:myKillerObject];
If the method got compiled.. It will get called. There is no "hiding" it. Even if not declared, the runtime "gives up" this information to any interested party. #see class-dump, if interested in learning more.

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

Cocoa: Build Warning that s Forward Declared Class's and #interface May not Exist

I am trying to build the Clustering Plug in my project under Leopard. I have following two questions.
In the project an interface class is defined as
#interface ClusteringController : NSWindowController
{
.......
.....
....
}
#end.
And this class is used in implementation class using forward declaration:
#class ClusteringController;
then in one function it is used as:
- (long) filterImage:(NSString*) menuName
{
ClusteringController *cluster = [[ClusteringController alloc] init];
[cluster showWindow:self];
return 0;
}
When I build this project it produces the warning:
warning: receiver 'ClusteringController' is a forward class and corresponding #interface may not exist
Also there is one more warning produced:
warning: no '-updateProxyWhenReconnect' method found
This warning is coming for the following line of code:
if(delegate) [delegate updateProxyWhenReconnect];
Can anybody help me to overcome these warnings?
A forward declaration is used when the header file will be imported after the interface. It looks to me that you've used the #class directive after the interface for the class itself.
The normal use of a forward class declaration looks like this:
#import "SomeSuperClass.h"
#class Forwardclass;
#interface SomeClass : SomeSuperClass
{
Forwardclass anIvar;
}
#property Forwardclass anIvar;
#end
#import "SomeClass.h"
#import "ForwardClass.h"
#implementation SomeClass
#synthesize anIvar;
-(void) setAnIvar:(ForwardClass *) aForwardClass;
#end
The #class directive is never used in an implementation (.m) file.
That's not what #class is for.
You use #class in the header file for another class, to tell the compiler that the class you're declaring does exist. Without it, the compiler would not know that that's a class name, and when you declare a variable as holding a pointer to an instance of that class, the compiler would think that you're just making up words. Using #class is called forward-declaring the class.
Your situation is different. You're in the implementation file for that class.
What the compiler needs from you now is the class's #interface. The warning is telling you that the compiler needs an #interface, but you haven't given it one (so, as far it knows, the #interface “may not exist”).
Normally, you would have written the #interface in a header file; how now to get it into the implementation file?
That's where the preprocessor comes in, with its #import directive. At the top of the implementation file (ClusteringController.m), import the header file:
#import "ClusteringController.h"
The preprocessor will replace this with the contents of that file, then hand the preprocessed code to the compiler, which will see the #interface there.

how to return C++ pointer in objective-C++

I have the following objective-C++ header with the simple method to return this pointer.
#interface MyObj
{
MyCPPObj * cpp;
}
-(MyCPPObj *) getObj;
I have created the simple method
#implementation MyObj
-(MyCPPObj *) getObj
{
return cpp;
}
Everything seems to work until I actually try to use the object in another file
newObj = [createdMyObj getObj];
It complains: error: cannot convert 'objc_object*' to 'MyCPPObje *' in initialization.
It seems that the method is return an objective-c object, but I specifically requested a C++ pointer.
MyCPPObj is an honest C++ class:
class MyCPPObj
{
public:
int x;
}
How can I fix that?
On my 10.6.3 machine, the following combination worked without any problem: aho.h
#import <Foundation/Foundation.h>
class MyCPPObj{
};
#interface MyObj:NSObject
{
MyCPPObj * cpp;
}
-(MyCPPObj *) getObj;
#end
and aho.mm
#import <Foundation/Foundation.h>
#import "aho.h"
void foo(){
MyObj*objcObj=[[MyObj alloc] init];
MyCPPObj*cppObj=[objcObj getObj];
}
Two pitfalls you might have fallen into:
Unlike C++, a class in Objective-C which doesn't inherit from NSObject won't work. (Well, you can make it work, but you don't want that usually.) Note the line #interface MyObj:NSObject.
To use NSObject, do #import <Foundation/Foundation.h>
Don't forget to use the extension .mm for Objective-C++ files.
Most likely you have forgotten to #import the header file with the #interface into the .mm file where you use getObj.
The error states what happens, and JeremyP is right on the money. When you forget to include a header file with the prototypes of the selectors, the compiler assumes the selector returns an object of type id. Well id is a typedef to objc_object*, which is incompatible with your C++ class. To fix the error, you simply need to include your header file in the file where you called getObj.