Error: Property implementation must have its declaration in '<classname>' interface or one of its extensions - objective-c

I have a Swift extension as follows:
#objc
protocol Themeable: class {
#objc var themeGradient: Gradient { get set }
}
In Objc, I have some view controllers adopting that protocol, using #synthesize for the property.
#import "MyProject-Swift.h"
#interface MyObjcViewController () <Themeable>
#end;
#implementation MyObjcViewController
#synthesize themeGradient;
...
#end;
When building I'm getting this error in the #synthesize line:
Error: Property implementation must have its declaration in interface
'MyObjcViewController' or one of its extensions
Is it possible to synthesize properties defined in Swift protocols?

Well, this is a bit embarrassing. While working on this, I contemplated the idea of delaying this protocol in Objc, and I had this left over somewhere in the code:
#protocol Themeable
#end;
This declaration was on a header file, and was not triggering a "Redeclaration" error :(
Removing the above declaration made the #synthesize work as intended.

Related

Swift cannot pass class conforming to protocol as function parameter to a function residing in Objective-C file

Hi I'm new to Swift but experienced with Objective-C.
I have a project that uses both Swift and Objective-C files (bridging and all).
Say I have a protocol called "fooProtocol" and a class "foo" that implements it. I am trying to pass an object of type "fooProtocol" from the Swift file as a parameter to the function inside the Objective-C file.
here is the Objective-C function inside class "tester":
-(void)setWithFoo:(id<fooProtocol>*)_foo{
}
here is the Swift code:
var myObject:fooProtocol = foo.init()
var objcObject:tester = tester.init()
objcObject.setWithFoo(_foo: myObject)
It first says "Cannot convert value of type "fooProtocol" to expected argument type "AutoreleasingUnsafeMutablePointer (obviously because it needs to be passed by reference, so...)
I then tried casting the parameter to this:
tester.setWithFoo(_foo: AutoreleasingUnsafeMutablePointer<fooProtocol>(myObject))
Now the error reads: "Cannot invoke initializer for type 'AutoreleasingUnsafeMutablePointer with an argument list of type '(fooProtocol)'
I have tried many more permutations and variations but I simply cannot stop the compiler error. For such a simple procedure as passing a polymorphic variable to a function in Objective-C file that expects that protocol id, Swift has made it a nightmare.
...Any help would be appreciated, thanks!
=== EDIT ===
Here are the declarations for the classes, now starting properly with caps
In the "FooProtocol.h" file:
#protocol FooProtocol
#end
In the "Foo.h" file:
#import <Foundation/Foundation.h>
#import "FooProtocol.h"
#interface Foo : NSObject <FooProtocol>
#end
In the "Foo.m":
#import "Foo.h"
#implementation Foo
#end
The "FooProtocol.h" file:
#import <Foundation/Foundation.h>
#protocol FooProtocol
#end
The "Tester.h" file:
#import <Foundation/Foundation.h>
#import "FooProtocol.h"
#interface Tester : NSObject
-(void)setWithFoo:(id<FooProtocol>*)_foo;
#end
The "Tester.m" file:
#import "Tester.h"
#implementation Tester
-(void)setWithFoo:(id<FooProtocol>*)_foo{
//do something with _foo
}
#end
And again the Swift code that can't compile:
var myObject:FooProtocol = Foo.init()
var objcObject:Tester = Tester.init()
objcObject.setWithFoo(AutoreleasingUnsafeMutablePointer<FooProtocol>(myObject))
You probably don't mean to say this:
-(void)setWithFoo:(id<FooProtocol>*)_foo;
It is very unusual to see an id* in Objective-C. In fact, it's so unusual that in all my years of programming Cocoa, I have never seen one.
You probably mean this:
-(void)setWithFoo:(id<FooProtocol>)_foo;
And then you will be able to say, on the Swift side:
objcObject.setWithFoo(myObject)

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

Error when compiling: No visible #interface declares the selector

In one class I have the following
AlertEditorContainerViewController.m
#import "AlertEditorContainerViewController.h"
#interface AlertEditorContainerViewController ()
-(void)swapViewControllers;
#end
#implementation AlertEditorContainerViewController
#synthesize currentSegueIdentifier;
#synthesize segIndex;
- (void)swapViewControllers
{
self.currentSegueIdentifier = ([self.currentSegueIdentifier isEqual: SegueIdentifierFirst]) ? SegueIdentifierSecond : SegueIdentifierFirst;
[self performSegueWithIdentifier:self.currentSegueIdentifier sender:nil];
}
#end
The in another class I try to call it
AlertEditorViewController.h
#interface AlertEditorViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
{
AlertEditorContainerViewController *containerViewController;
}
AlertEditorViewController.h
#import "AlertEditorViewController.h"
#implementation AlertEditorViewController
- (IBAction)segmentSwitchValueChanged:(id)sender
{
[containerViewController swapViewControllers];
}
#end
This gives the error "No visible #interface for AlertEditorContainerViewController declares the selector swapViewControllers'
I have looked up all of the other similar queries and they all seem to point at typos etc which I can't find in my code.
Declare -(void)swapViewControllers in your AlertEditorContainerViewController.h file, not your .m file.
For information on this problem, you'll want to check out this Stack Overflow question, but in short, by declaring the method within the #interface block located in your .m file, you're effectively making it a private method (inaccessible by other implementation files). From the link:
The interface section in the implementation file allows you to declare variables, properties, and methods that are private, meaning that they won't be seen by other classes.
The compiler knows it's there within the scope of that particular file, but other files can't access or even see that method as being defined.

categories for protocols and warnings "class does not implement protocol"

Well, I have these two protocols:
#protocol ivAuthorizationProtocol <NSObject>
-(void)loginReply:(ivSession*)session;
#end
#protocol ivServerListsProtocol <NSObject>
-(void)serverListLoaded:(NSArray*)serverList;
#end
and have class
#interface ivClientAppDelegate : NSObject <UIApplicationDelegate>
...
#end
#implementation
...
-(void)authorizeWithLogin:(NSString*)login andPassword:(NSString*)password
{
self.login = login;
self.password = password;
// !!! delegate in the next call should conform to ivAuthorizationProtocol,
// so i get warning "class does not implement protocol ivAuthoriaztionProtocol" here
[_apiWrapper authorizeWith:login andPassword:password forDelegate:self];
}
...
#end
I want to put the implementation of the protocol's methods in separate files (categories) so not to mess up the main implementation file. For example, the header of the category for implementation of ivAuthorizationProtocol looks like this:
#import "ivClientAppDelegate.h"
#interface ivClientAppDelegate (ivAuthorizationResponder) <ivAuthorizationProtocol>
-(void)loginReply:(ivSession*)session;
#end
So, the question is - how can I get rid of the warning I get in the main implementation file? How can I tell the compiler that methods conforming to the protocol are located in categories?
Thanks in advance!
You could use a cast to silence the warning:
[_apiWrapper
authorizeWith:login
andPassword:password
forDelegate:(id<ivAuthorizationProtocol>)self
];
Other than that, you can't do what you want without getting different warnings (unimplemented methods). Normally you would specify the protocol in the interface:
#interface ivClientAppDelegate : NSObject <UIApplicationDelegate,ivAuthorizationProtocol
But then you would need to implement the methods in you main #implementation block.
Please note that by convention class and protocol names should start with an uppercase character.
Why don't you consider doing it like this:
#interface ivClientAppDelegate : NSObject <UIApplicationDelegate, ivAuthorizationProtocol >
Declaring protocol method as optional will fix the issue.

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.