Objective-C: can initialize one class but not the other - objective-c

I have some objective-C code with a few classes. I'm trying to initialize each of the first two classes within the third class. One works fine, turns the right color in Xcode and allows me to jump to the definition. The other for some reason doesn't. I've poured over it but can't see what distinguishes the two.
MainClass.m:
#import "Class1.h"
#import "Class2.h"
#implementation MainClass
Class1 *class1 = [Class1 new];
Class2 *class2 = [Class2 new];
#end
Class1.h:
#ifndef Class1_h
#define Class1_h
#interface Class1 : NSObject
#end
#endif
Class2.h:
#ifndef Class2_h
#define Class2_h
#interface Class2 : NSObject
#end
#endif
There's no difference in header files of Class1.h and Class2.h. Both are imported into the MainClass.m But for some reason Class2 isn't recognized in MainClass.m, yields "Initializer element is not a compile-time constant" on Build+Run and doesn't allow me to command-click and jump to the definition.
I'm not sure where to look at this point. I've copied and pasted the code from the Class1.m file into Class2.m only changing the #import Class2.h header import and #implementation Class2 lines to make sure its not something in the .m files...problem persists.

You have an apostrophe instead of a double-quote at the end of your second import.

You might have a lingering #define of Class2_h somewhere. (This can happen if you use this #ifndef/#define/#endif pattern, especially if cutting and pasting code.)
For what it’s worth, you really don't need this #ifndef/#define/#endif pattern around your #interface references. Often C programmers are used to using this pattern a lot, but it’s just not needed in Objective-C class definitions.
For example, consider scenario where Class1 had a property that was a Class2:
// Class1.h
#import "Foundation/Foundation.h"
#import "Class2.h"
#interface Class1 : NSObject
#property (nonatomic, strong) Class2 *class2;
#end
And
// Class2.h
#import "Foundation/Foundation.h"
#interface Class2 : NSObject
#end
Then MainClass can import both headers without incident (even though Class1.h currently imports Class2.h already):
// MainClass.m
#import "MainClass.h"
#import "Class1.h"
#import "Class2.h"
#implementation MainClass
- (void)foo {
Class1 *class1 = [Class1 new];
Class2 *class2 = [Class2 new];
NSLog(#"Class1: %#", class1);
NSLog(#"Class2: %#", class2);
}
#end
You would have thought that this redundant #import "Class2.h" would cause problems, but it doesn’t. Objective-C tried to get us out of worrying about all of these #define references.
Now, that having been said, using that above example, Class1.h might not even #import the Class2.h file, at all, but it might just do a forward declaration of the class. And if Class1 implementation needed to interact with Class2 objects, you’d do the #import of Class2.h in Class1.m, not Class1.h:
// Class1.h
#import "Foundation/Foundation.h"
#class Class2;
#interface Class1 : NSObject
#property (nonatomic, strong) Class2 *class2;
#end
But regardless, we just don't tend to use the #ifndef/#define/#endif pattern in Objective-C.

Related

Swift protocol in Objective-C category

I have a protocol defined in Swift:
#objc public protocol UploadProtocol: class {
func isUploaded() -> Bool
...
}
I'm importing my ProjectName-Swift.h file in my ProjectName_Prefix.pch file (old project).
In Objective-C I have a category on a class which implements the protocol. I'm trying to figure out how to let the compiler know about that implementation. This is what I have been doing:
// Person+Upload.h
#import "Person.h"
#interface Person (Upload)
- (BOOL)isUploaded;
#end
// Person+Upload.m
#import "Person+Upload.h"
#implementation Person (Upload)
...
#end
This gives me:
Cannot find protocol definition for 'UploadProtocol'
I can only think of three other ways of setting this up and all of them have problems. What am I missing?
First Way (Apple Recommended)
In Using Swift with Cocoa and Objective-C (Swift 2.2), Apple says, "An Objective-C class can adopt a Swift protocol in its implementation (.m) file by importing the Xcode-generated header for Swift code and using a class extension." But their example is for a standard class. If I try to do this with my category:
// Person+Upload.h
#import "Person.h"
#interface Person (Upload)
- (BOOL)isUploaded;
#end
// Person+Upload.m
#import "Person+Upload.h"
#interface Person (Upload) <UploadProtocol>
#end
#implementation Person (Upload)
...
#end
This results in:
Duplicate definition of category 'Upload' on interface 'Person'
Second Way
Ok, so I want to avoid defining the upload class twice. So I'll remove it from the .h.
// Person+Upload.h
#import "Person.h"
#interface Person ()
- (BOOL)isUploaded;
#end
// Person+Upload.m
#import "Person+Upload.h"
#interface Person (Upload) <UploadProtocol>
#end
#implementation Person (Upload)
...
#end
In this case I get:
Category is implementing a method which will also be implemented by its primary class
I'm currently declaring the method in the .h so that other classes can call some of those methods without casting to the protocol to access that method.
Third Way
If I leave the category name in the .h but take it off in the .m
// Person+Upload.h
#import "Person.h"
#interface Person (Upload)
- (BOOL)isUploaded;
#end
// Person+Upload.m
#import "Person+Upload.h"
#interface Person () <UploadProtocol>
#end
#implementation Person (Upload)
...
#end
Then I get:
Category is implementing a method which will also be implemented by its primary class
Is the only solution to cast it to the protocol every time? Adding this type of line in multiple places seems like a code smell:
Person <Upload> *s = (Person <Upload> *)self;
Any other solutions?
Thanks for the interesting question!
Your initial approach will actually work with an addition of a forward declaration of the protocol:
// Person+Upload.h
#import "Person.h"
#protocol UploadProtocol; // NOTE THIS!!!
#interface Person (Upload) <UploadProtocol>
//- (BOOL)isUploaded; // This is not really needed
#end
// Person+Upload.m
#import "Person+Upload.h"
#import "...-Swift.h" // IMPORTANT!!!
#implementation Person (Upload)
// HERE you implement isUploaded, of course.
...
#end
This will still cause a compiler warning Cannot find protocol definition for 'UploadProtocol', but it should work.
The Apple-recommended way also works, the Duplicate definition of category is just a warning, but Person won't be recognized as conforming to the protocol by Swift code, even though its conformance will be recognized by Objective-C. The initial approach will be fine in Swift, too.

Cannot find interface declaration for superclass of

I know this is a common subject but I did not find any answer to help me out with this problem.
Well, I do have (by now) 3 .h files,
One is the superclass of the two others.
Superclass : ExportationAutoFilterNew
#import <Foundation/Foundation.h>
#import <HIDDEN/PluginFilter.h>
#class MyOutlineView;
#interface ExportationAutoFilterNew : PluginFilter
#property (assign, nonatomic) NSUserDefaults *prefs;
#property (assign, nonatomic) MyOutlineView *databaseOutline;
#end
Then, sub-classes : DetectNewExams & ExportExams
#import <Foundation/Foundation.h>
#import <HIDDEN/PluginFilter.h>
#import "ExportationAutoFilterNew.h"
#interface DetectNewExams : ExportationAutoFilterNew
- (void)detectExams:(NSDate*)currentDate timeInterval:(double)timeInterval afterExitHidden:(BOOL)check;
And
#import <Foundation/Foundation.h>
#import <HIDDEN/PluginFilter.h>
#import "ExportationAutoFilterNew.h"
#interface ExportExams : ExportationAutoFilterNew
- (void)exportExams:(NSManagedObject*)curObj;
The .m goes like this
Superclass : ExportationAutoFilter
#import <HIDDEN/PreferencesWindowController.h>
#import <HIDDEN/browserController.h>
#import "ExportationAutoFilterNew.h"
#import "DetectNewExams.h"
#implementation ExportationAutoFilterNew
Xcode for this file (ExportationAutoFilterNew.m) :
Instance method '-detectExams:timeInterval:afterExitHidden:' not found (return type defaults to 'id')
For the call of :
[self detectExams:lastExportDate timeInterval:0 afterExitHidden:YES];
Sub-classes : DetectNewExams
#import <HIDDEN/PreferencesWindowController.h>
#import <HIDDEN/browserController.h>
#import "DetectNewExams.h"
#import "ExportExams.h"
#implementation DetectNewExams
In this file (DetectNewExams.m), Xcode says :
Instance method '-exportExams:' not found(return type defaults to 'id')
Calling :
[self exportExams:curObj];
And then : ExportExams
#import <HIDDEN/PreferencesWindowController.h>
#import <HIDDEN/browserController.h>
#import "ExportExams.h"
#implementation ExportExams
I'm wasting hours on this thing and I can't figure the problem out, may you help me ? I looked up for compiling circle but I don't think I created one with my imports ..
Thanks.
Your interface is not properly declared. Try this.
#interface ExportationAutoFilterNew : PluginFilter
#property (nonatomic) NSUserDefaults *prefs;
#property (nonatomic) MyOutlineView *databaseOutline;
#end
Now that you have posted the actual error, this becomes more clear. But you still haven't posted enough context.
Instance method '-detectExams:timeInterval:afterExitHidden:' not found (return type defaults to 'id')
That means that the method declaration hasn't been seen at the time the code was compiled or the method is declared on some class that whatever was being called is not an instance of.
Since you haven't shown the call site or the declaration of the variable being called, this is a guess. The method is declared on the DetectNewExams class. I'd bet you have a variable that points to an instance of ExportationAutoFilterNew and, therefore, the compiler is correctly warning that the method doesn't exist on the class.

Can I hide my superclass from the users of my class?

Is it possible to encapsulate the fact that my class is derived from a certain superclass? Something like:
#class NoneOfYourBusiness;
#interface MyClass : NoneOfYourBusiness
#end
The compiler doesn’t like this: Attempting to use the forward class 'NoneOfYourBusiness' as superclass of 'MyClass'.
You could add some indirection; a dummy superclass in the inheritance tree, between MyClass and RealSuperclass:
Private header, HiddenSuperclass.h, with corresponding implementation file
#import <Foundation/Foundation.h>
#interface HiddenSuper : NSObject
- (void)makePancakes;
#end
Header for dummy class, corresponding empty implementation
#import <Foundation/Foundation.h>
#import "HiddenSuper.h"
#interface DummySuper : HiddenSuper
// Nothing to see here, folks!
#end
Then your public class's header:
#import "DummySuper.h"
#interface PublicSubclass : DummySuper
- (void)fixBreakfast;
#end
And the implementation, hidden by compilation:
#import "PublicSubclass.h"
#import "HiddenSuper.h"
#implementation PublicSubclass
- (void)fixBreakfast
{
[self makePancakes];
}
#end
Two answers
The requirement makes no sense. Client code can see the super class does not mean anything because it should be empty.
i.e. Thats all they can see
#interface NoneOfYourBusiness : NSObject
#end
#interface MyClass : NoneOfYourBusiness
- (void)publicMethod;
#end
because you should put all private / internal method / variable in private header / implementation file.
Ok you really need to hide it for some reason, then hide everything
public header
#interface MyClass : NSObject
- (void)publicMethod;
#end
private header / implementation file
#interface NoneOfYourBusiness : NSObject
#end
#interface MyClassImpl : NoneOfYourBusiness
- (void)publicMethod;
#end
#interface MyClass ()
#property (strong) MyClassImpl *impl;
#end
#implementation
- (id)forwardingTargetForSelector:(SEL)aSelector
{
return self.impl;
}
#end
you can even make MyClass inherited from NSProxy to make it a real proxy object

Hiding properties from public framework headers, but leaving available internally

I need to have property in class that is excluded from public framework headers, but it is available for use internally in other framework classes.
What I did right now is:
MyClass.h:
#interface MyClass: NSObject
#end
MyClass+Internal.h
#interface MyClass (Internal)
#property (nonatomic, copy) NSString *mySecretProperty;
#end
MyClass.m
#import "MyClass.h"
#import "MyClass+Internal.h"
#interface MyClass ()
#property (nonatomic, copy) NSString *mySecretProperty;
#end
#implementation MyClass
#end
And I can use private property like:
MyOtherClass.m:
#import "MyClass.h"
#import "MyClass+Internal.h"
#implementation MyOtherClass
- (void)test {
MyClass *myClass = [MyClass new];
NSLog(#"%#", myClass.mySecretProperty)
}
#end
But what I don't like about this setup is that I have duplicate declaration of property in my Internal Category and inside of anonymous Category.
Is there a way to improve this setup?
I think you could do with the class extension only, there is no need to use a category. The quick fix would be to remove the category name from the parenthesis, transforming it into the class extension, then remove the class extension declaration from the .m file.
After this you only import the extension header in your framework classes and you make sure it is a private header of your framework.
MyClass.h
#interface MyClass: NSObject
#end
MyClass+Internal.h
#import "MyClass.h"
#interface MyClass ()
#property (nonatomic, copy) NSString *mySecretProperty;
#end
MyClass.m
#import "MyClass.h"
#import "MyClass+Internal.h"
#implementation MyClass
#end
MyOtherClass.m:
#import "MyClass.h"
#import "MyClass+Internal.h"
#implementation MyOtherClass
- (void)test {
MyClass *myClass = [MyClass new];
NSLog(#"%#", myClass.mySecretProperty)
}
#end
The key is understanding the difference between categories and class extensions, see here: https://stackoverflow.com/a/4540582/703809

Expose a private Objective-C method or property to subclasses

According to some official talk, a class in Objective-C should only expose public methods and properties in its header:
#interface MyClass : NSObject
#property (nonatomic, strong) MyPublicObject *publicObject;
- (void)publicMethod;
#end
and private methods/properties should be kept in class extension in .m file:
#interface MyClass()
#property (nonatomic, strong) MyPrivateObject *privateObject;
- (void) privateMethod;
#end
and I don't think there is a protected type for things that are private but accessible from subclasses. I wonder, is there anyway to achieve this, apart from declaring private properties/methods publicly?
One way to solve this is to re-declare the property in your subclass's class extension, and then add an #dynamic statement so that the compiler won't create an overriding implementation of that property. So something like:
#interface SuperClass ()
#property (nonatomic, strong) id someProperty;
#end
....
#interface SubClass ()
#property (nonatomic, strong) id someProperty;
#end
#implementation SubClass
#dynamic someProperty;
#end
This obviously isn't ideal because it duplicates a privately visible declaration. But it is quite convenient and helpful in some situations so I'd say evaluate on a case-by-case basis the dangers involved in this duplication vs. exposing the property in the public interface.
An alternative - that is used by Apple in UIGestureRecognizer - is to declare the property in a separate category header file explicitly named as "private" or "protected" e.g. "SomeClass+Protected.h". That way, other programmers will know they ought not import the file. But, if you don't control the code you're inheriting from, that's not an option.
This is possible by using a class extension (not category) that you include in the implementation files of both the base class and subclasses.
A class extension is defined similar to a category, but without the category name:
#interface MyClass ()
In a class extension, you can declare properties, which will be able to synthesize the backing ivars (XCode > 4.4 automatic synthesis of the ivars also works here).
In the extension class, you can override/refine properties (change readonly to readwrite etc.), and add properties and methods that will be "visible" to the implementation files (but note that the properties and methods aren't really private and can still be called by selector).
Others have proposed using a seperate header file MyClass_protected.h for this, but this can also be done in the main header file using #ifdef like this:
Example:
BaseClass.h
#interface BaseClass : NSObject
// foo is readonly for consumers of the class
#property (nonatomic, readonly) NSString *foo;
#end
#ifdef BaseClass_protected
// this is the class extension, where you define
// the "protected" properties and methods of the class
#interface BaseClass ()
// foo is now readwrite
#property (nonatomic, readwrite) NSString *foo;
// bar is visible to implementation of subclasses
#property (nonatomic, readwrite) int bar;
-(void)baz;
#end
#endif
BaseClass.m
// this will import BaseClass.h
// with BaseClass_protected defined,
// so it will also get the protected class extension
#define BaseClass_protected
#import "BaseClass.h"
#implementation BaseClass
-(void)baz {
self.foo = #"test";
self.bar = 123;
}
#end
ChildClass.h
// this will import BaseClass.h without the class extension
#import "BaseClass.h"
#interface ChildClass : BaseClass
-(void)test;
#end
ChildClass.m
// this will implicitly import BaseClass.h from ChildClass.h,
// with BaseClass_protected defined,
// so it will also get the protected class extension
#define BaseClass_protected
#import "ChildClass.h"
#implementation ChildClass
-(void)test {
self.foo = #"test";
self.bar = 123;
[self baz];
}
#end
When you call #import, it basically copy-pastes the .h file to where you are importing it.
If you have an #ifdef, it will only include the code inside if the #define with that name is set.
In your .h file, you don't set the define so any classes importing this .h wont see the protected class extention.
In the base class and subclass .m file, you use #define before using #import so that the compiler will include the protected class extension.
While the other answers are correct, I'd like to add...
Private, protected and public are available for instance variables as such:
#interface MyClass : NSObject {
#private
int varA;
#protected
int varB;
#public
int varC;
}
#end
Your only choice is to declare it as public in the header file. If you want to at least keep some method separation, you can create a category and have all your protected methods and attributes there, but in the end everything will still be public.
#import "MyClass.h"
#interface MyClass (Protected)
- (void) protectedMethods;
#end
Simply create a .h file with your class extension. Import this into your .m files. Incidentally, this is a great way to test private members without breaking encapsulation (I'm not saying you should test private methods :) ).
// MyClassProtectedMembers.h
#interface MyClass()
#property (nonatomic, strong) MyPrivateObject *privateObject;
- (void) privateMethod;
#end
/////////////////
#import "MyClassProtectedMembers.h"
#implementation MyClass
// implement privateMethod here and any setters or getters with computed values
#end
Here's a gist of the idea: https://gist.github.com/philosopherdog/6461536b99ef73a5c32a
I see good answers for making properties visible, but I don't see exposing the methods addressed very clearly in any of these answers. Here is how I have successfully exposed private methods to the subclass using a Category:
SomeSuperClass.m:
#implementation SomeSuperClass
-(void)somePrivateMethod:(NSString*)someArgument {
...
}
SomeChildClass.h
#interface SomeChildClass : SomeSuperClass
SomeChildClass.m
#interface SomeSuperClass (exposePrivateMethod)
-(void)somePrivateMethod:(NSString*)someArgument;
#end
#implementation SomeChildClass
-(void)doSomething {
[super somePrivateMethod:#"argument"];
}
#end
That's because there's not even a real distinction between private and public. While the compiler may warn you about an interface missing a certain method or instance variable, your program will still work.