Where is the Class class declared/how to forward declare it? - objective-c

I cannot compile my because of this error in my header:
error: expected identifier [1]
-(void) removeAllEntitiesOfClass:(Class)class;
with the caret pointing to the lowercase class.
Removing this function makes it compile again.
My class is a subclass of NSObject, which has public methods that use Class, so I thought this would automagically be declared.
I also tried changing Class to Class* and forward declaring with #Class Class, and this doesn't work - it says it is a redefinition because I am changing the type. Apparently Class is a typedef'd struct pointer. I'm not sure how to forward declare that here, and I seem to recall it can be nasty business to forward declare a pointer typedef. Please correct me if I'm wrong, and tell me what file to import or how to forward declare.
#interface GameState : NSObject {
...
}
...
-(void) removeAllEntitiesOfClass:(Class)class;
#end

I suspect your header is visible in an Objective-C++ translation. In C++, class is a keyword. To fix this, change the parameter's name from class to some non-keyword.

Related

Resolving Swift.h and Bridging-Header.h circular references involving enums

I have an Objective-C header that has to be used by a Swift class. However, this header has to use the Swift.h file for an enum declared in a Swift file. In other words, the setup is as follows:
MPViewController.h
#import "MyProject-Swift.h"
#interface MPViewController: UIViewController
#property (nonatomic, assign) MPSomeEnum theEnum;
...
#end
MyProject-Bridging-Header.h
...
#import "MPViewController.h"
...
SomeEnum.swift
#objc enum MPSomeEnum: Int {
...
}
When compiling the code, I get three errors:
'MyProject-Swift.h' file not found
Failed to emit precompiled header [Xcode DerivedData folder]/[...]/MyProject-Bridging-Header-swift_[...].pch for bridging header [Project folder]/MyProject-Bridging-Header.h
Unknown type name 'MPSomeEnum'
Am I correct to assume that this stems from the circular reference between MyProject-Swift.h and the bridging header MyProject-Bridging-Header.h? From looking at a similar question one solution is to use forward declaration. However, it doesn't seem possible to forward declare an enum, so perhaps the only way to do this is to move the enum definition to an Objective-C file altogether?
TL&DR; As you suspected, you need to either move the enum declaration to Objective-C, or migrate the class to Swift.
Forward declarations of enums is possible in Objective-C:
#property SomeEnum someProperty;
- (void)doSomethingWithEnum:(enum SomeEnum)enumValue;
However correct Cocoa enums are typedefs to NSInteger: typedef NS_ENUM(NSInteger, MyEnum), and the enum keyword doesn't hold enough information for how much space to allocate when using it, so you'll get into all kind of compiler error when you want to use declarations like this. Thus an enum declared in Swift is not forward declarable in Objective-C.
Now, if you really want to keep the enum definition in Swift, you could use a workaround, and declare it as NSInteger in Objective-C, while providing a specialized property in Swift:
// NS_REFINED_FOR_SWIFT imports this in Swift as __theEnum
#property(nonatomic, assign) NSInteger theEnum NS_REFINED_FOR_SWIFT;
extension MPViewController {
// we provide a wrapper around the Objective-C property
var theEnum: MPSomeEnum {
// this uses a forced unwrap, beware :)
return MPSomeEnum(rawValue: theEnum)!
}
}

Calling objective-c method from Swift error

I get an error when I try to call objective-c method from swift.
my objective-c .h class:
#class myType;
#interface myClass : NSObject
- (myType *)myMethod;
then I will create an object form myClass and try to call myMethod in swift (I have declared anObject of type myClass):
let a = anObject.myMethod();
but I get an error:
Value of type 'myClass' has no member 'myMethod'
If I change myType to something else, the error goes away. So it should be a problem of not recognizing myType in swift..
I appreciate any help
#class myType;
is only a "forward declaration" of that class. In order to call the
- (myType *)myMethod;
method from either Objective-C or Swift, the compiler needs to know the
actual interface declaration of that class. So "myType.h" or whatever
file contains
#interface myType : NSObject
// ...
#end
must be included from the bridging header file.
Remark: Class names should start with a capital letter.
turned out the real problem for me was something else!
I had to simply delete the derived data:
Window -> Projects -> Derived Data -> Delete
Clean Project
Quit Xcode
Open Xcode
Build Project
Apparently, using swift I have to these steps more often..

Implementing NSCoding protocol

I'm working on a obj-c project and I want to implement the NSCoding protocol for a class, but I can't get it right. The code looks like this:
#include <Foundation/Foundation.h>
class Object: NSObject, NSCoding {
//Somecode
}
And I get the error: "Base specifier must name a class" and "Expected class name". What am I doing wrong?
You are declaring a C++ class, not a Objective-C one, and you cannot have inheritance from one language to another. You'll need to change your class declaration to something like
#interface Object: NSObject <NSCoding> {
// iVar declarations
}
// method and property declarations
#end
Although not sure how much it will help if your class already has defined C++ methods, as you'll need to port those one to Objective-C definitions.
I highly recommend you go through the link I posted in my comments, and read Apple's documentation on working with classes and objects. This will help you with the transition.

Objective C - Error with custom return type?

I'm very new to Objective-C, so this is probably very basic.
Anyhow, I am trying to specify a custom return type in my class, and I keep getting errors that the class either needs an asterisk* or is not considered a type at all. I read that you need to use #class instead of #import in your header files, but that doesn't seem to help in this case. What else am I doing wrong?
Here is my code:
#import <Foundation/Foundation.h>
#class Room;
#interface LevelData : NSObject {
#private
NSArray *data;
Room *currentRoom;
}
+(void)initialize;
+(*Room)getCurrentRoom;
#end
Thanks a bunch!
change that one line to:
+(Room *)getCurrentRoom;
and see if that compiles. Room * indicates you're returning a pointer to a Room Objective-C object.
The asterisk should go after the class name, like a standard C-style
pointer.
Class methods should return a value,
usually a pointer to an object of the same class, so if you do use
initialize you'll want it to return a Room*.
Good coding practice is to override -(Class *) init;, but
only if you need to. This is because the first thing you (or someone
else using your code) should/will do when using an object (usually)
is to call some form of [[Class alloc] init]. If they call this
when you have a special initialize function, it will call the
NSObject -(NSObject *)init; method instead, and your instance
variables won't get setup.

Is it possible to declare a method as private in Objective-C?

Is it possible to declare a method as private in Objective-C?
If you're working in Objective-C 2.0, the best way to create methods that are "hard" for others to call is to put them in a class extension. Assuming you have
#interface MyClass : NSObject {
}
- (id)aPublicMethod;
#end
in a MyClass.h file, you can add to your MyClass.m the following:
#interface MyClass () //note the empty category name
- (id)aPrivateMethod;
#end
#implementation MyClass
- (id)aPublicMethod {...}
- (id)aPrivateMethod {...} //extension method implemented in class implementation block
#end
The advanage of a class extension is that the "extension" methods are implemented in the original class body. Thus, you don't have to worry about which #implementation block a method implementation is in and the compiler will give a warning if the extension method is not implemented in the class' #implementation.
As others have pointed out, the Objective-C runtime will not enforce the privateness of your methods (and its not too hard to find out what those methods are using class dump, even without the source code), but the compiler will generate a warning if someone tries to call them. In general, the ObjC community takes a "I told you not to call this method [by putting it in a private class extension or category or just by documenting that the method is private] and you called it anyways. Whatever mess ensues is your fault. Don't be stupid." attitude to this issue.
No, any object can send any message to any other object. You can, however, put the method in a category that's part of the class's implementation file. That way, you'll get a "Class may not implement this method" warning if you try to call it anywhere else. That's the normal way of making a method "private."
There is nothing that will prevent the method being called (since objective-c is message based anything can be sent any message), but you can declare them outside of the header so they are not visible and the compiler will generate warnings if used.
This works for both class and instance methods.
E.g.
#import "SomeClass.h"
// Interface for hidden methods
#interface SomeClass (hidden)
+(void) hiddenClassMethod;
-(void) hiddenInstanceMethod;
#end
Note: Do NOT declare variables like this or they will become class-variables - e.g. only one variable will be used by all instances.
You can do so by using categories. I've got a fuller description in my answer to this SO question.
As has been said, you can't stop anyone sending a message to a selector, but by using categories you can reduce the visibility of these functions.
Also, you can have more than one category extending a class. So, by using informative category names you can group private functions into related blocks, improving the self-documenting nature of your code.
As others mentioned, you can't have code that's
a method, and
impossible to call from outside a class.
Folks have already pointed out that you can abandon point 2, and get a method that's hard-but-not-impossible to call. Alternatively, why not abandon point 1?
static id myPrivateMethod(MyObject *me, int arg1, id arg2) { ... }
Now the code can only be called from within same file. You don't get any of the magic private-member access you can get with a method, so this is by no means a perfect solution. But there's no better way to achieve privacy.
To implement hidden methods (instance and/or class)
// ===========================
// = File: SomeClass.m
// ===========================
#import "SomeClass.h"
// =================================
// = Interface for hidden methods
// =================================
#interface SomeClass (hidden)
-(void) hiddenInstanceMethod;
#end
// ================================
// = Implementation for SomeClass
// ================================
#implementation SomeClass
-(void) hiddenInstanceMethod
{
printf( "Hidden instance method\n" );
}
-(void) msg
{
printf("Inside msg()...\n");
[self hiddenInstanceMethod];//private method calling
}
#end
http://macdevelopertips.com/objective-c/private-methods.html
reffer this link it will be helpful .