Generic subclasses of '#objc' classes cannot have an explicit '#objc' attribute - objective-c

I am trying to add swift library in my objective c project
https://github.com/vimeo/VimeoUpload
I have already added #import “-Swift.h” in my project
to subclass VimeoUpload, I am adding #objc in class definition and it gives me following error
Generic subclasses of '#objc' classes cannot have an explicit '#objc' attribute because they are not directly visible from Objective-C.

Objective-C doesn't support Swift Generics, that is why you can't add #objc directive to your class.

Related

Why does a class become public if you inherit from NSObject in Swift?

I'm working on a framework.
The library is written in Swift and I notice that when a class inherits from NSObject or conforms to NSObjectProtocol, its declaration can be found in *.framework/Headers/*-Swift.h.
This class is available outside of the module in Objective-C code, so it became public.
Why does it happen if the access level is internal?
Internal Swift classes need to be available to the Objective-C code of that framework, however the only way Objective-C code can access the Swift classes is by importing the -Swift.h header file.
Now, how can a Swift class be visible to Objective-C: it either needs to inherit NSObject, or conform to NSObjectProtocol. If any of these two conditions is fulfilled, and the class declaration is not decorated with #nonobjc/private/fileprivate, then it will be exported to Objective-C via the -Swift.h module header.
This is why any Swift classes that are exportable to Objective-C will automatically be present in the discussed header file. It's an (unfortunate) coincidence that for frameworks this results in the class being publicly available (due to the fact that any Objective-C declarations that appear in a header are public).
Now, if you want your class to not end up in the -Swift.h header file, but still want to keep the NSObject(Protocol) inheritance/conformance, a workaround would be to make your class generic, thus prohibiting its exposure to Objective-C. Note that this will also prevent the class from being available to Objective-C code in the same framework.
// the generic argument doesn't matter, it's only used to make the class
// Swift-only
class MyClass<T>: NSObject { }
The caveat would be that every time the class is used, you will need to specify a value for the generic argument. This can be avoided by adding an intermediary base class:
// just a class that inherits NSObject, but is not exported in the -Swift header
class Empty<T>: NSObject { }
class MyClass: Empty<String> { }

Error when implementing Objective-C protocol in a Swift Category

I am trying to convert my existing Objective C code to swift. I have a BaseClass 'A' which implements a protocol 'P' by using different Categories for proper code separation. It works fine when I use Objective Categories but when I implement a procotol method (method:) in a swift extension, I get the following error:
Method 'method:' with Objective-C selector 'method:' conflicts with previous declaration with the same Objective-C selector. Not sure how to resolve this issue? Is it not possible to do this Swift

Exclude Objective C Category from some Swift classes

In objective C, a Category will only "be used" in a class if I import it. So if I have a Category NSString+category, I have to #import NSString+category.h in each class I want to use it.
I have such a Category, and some of the classes I want to use it in are written in Swift. If I expose this category to Swift by putting it in the Bridging header, ALL swift classes will use it. How can this be avoided?
Note: My Category is actually on UIViewController and the code I have put there must only be used by SOME ViewControllers. It feels wrong and unneccessary to use this Category on the "other" ViewControllers.
Your base assumption is incorrect:
In objective C, a Category will only "be used" in a class if I import it
The methods in a category are present on the class if the category is compiled. Importing the header makes the method names visible; without that the compiler will give you a warning if you try to send a message using one of those names. (You can call the methods using performSelector: or the runtime library if you're determined.)
The same is true of your Swift class, and because of the way Objective-C headers are brought in to Swift, I don't believe there's a way to limit the methods' visibility in your Swift code.

Using #objc attribute for a Swift class that doesn’t inherit from an Objective-C class

The following paragraph from the section on Interoperability of the Using Swift with Cocoa and Objective-C (Swift 2.1) documentation seems to suggest that there is a way to use a Swift class that does not inherit from an Objective-C class for interoperability.
When you create a Swift class that descends from an Objective-C class, the class and its members—properties, methods, subscripts, and initializers that are compatible with Objective-C—are automatically available from Objective-C. In some cases, you need finer grained control over how your Swift API is exposed to Objective-C. You can use the #objc attribute if your Swift class doesn’t inherit from an Objective-C class, or if you want to change the name of a symbol in your interface as it’s exposed to Objective-C code.
And I attempted the following:
import Foundation
#objc class FooBar {
#objc var name: String;
init() {
name = "Hello World!"
}
}
But unfortunately, it gives a compilation error: Only classes that inherit from NSObject can be declared #objc
Am I misinterpreting something?
Take a look at this thread on the Apple Developer Forums.
Basically what you say was possible in Xcode <=6, but removed on Xcode 7
Pretty much yes. #objc on Swift-rooted classes never quite behaved like an NSObject-rooted class, leading to various weirdness in the generated header and at runtime. You can still treat any Swift class instance as an AnyObject, mark methods and properties on a Swift class as #objc, and conform to Objective-C protocols; the class just isn't exposed in the generated header and doesn't default to having its members available in Objective-C.

Objective-C protocol not recognized in Swift

I am working in an app written in Objective-C and we would like to begin integrating some Swift into it.
I have written a simple view controller class in Swift and to work in the app it must conform to a protocol that was written in Objective-C. In my Swift class I have the following declaration:
#objc class SwfViewController: UIViewController, theProtocolName {
//some code
}
In my bridging header file I have the class name of the protocol referenced.
#import "theProtocolName.h"
I have implemented all of the required methods listed in the protocol, yet still I get an error saying
SwfViewController does not conform to protocol 'theProtocolName'
I'm fairly new to Swift and could have easily left out something. Any suggestions of what to check? Thanks!
You should take into account that Swift signature for methods is slightly different from objective-c. For example:
A protocol like this:
#protocol MyProtocol <NSObject>
- (void)didFinish:(MyClass *)class withError:(id)errorMessage;
#end
A class that conforms to this protocol in Swift should be:
#objc class SwfViewController: UIViewController, MyProtocol {
func didFinish(whatEveryouWant1: UIViewController!, withError whatEverYouWant2: AnyObject!){
}
}
Please note id becomes AnyObject and Obj-C references are translated with ! as implicitly unwrapped optionals.
Generally this error means that your class is missing required methods which is the part of the point of the protocol. The class seems to realize that it need to follow the protocol you've told it about, but now need to define the required pieces.
You should be able to expand the error message by clicking on it to find out which pieces are missing.