#objc error when migrated to Swift 2 - ios

I had a Swift class declared like this:
#objc class MyHelper {
// class code
}
I had to do this to access such class from Objective-C classes, since I'm mixing languages in my project. Now that I upgraded to Xcode 7, I get this error:
Only classes that inherit from NSObject can be declared #objc
And such class is not known by my Objective-C classes anymore. I guess that then I should inherit my Swift class from NSObject, will that have any impact in the way the app was working?
Thanks

See the Apple staff SevenTenEleven's reply in the Apple Developer Forum.
He mentioned that this is because of #objc on Swift-rooted classes never quite behaved like an NSObject-rooted class, leading to various weirdness in the generated header and at runtime.
We 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.

Related

Question about Importing Swift code into objective c code

I read this documentation for importing swift code into objective c.
https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/importing_swift_into_objective-c
I have a few questions.
Can I put #objc annotation for a Struct?
Do I need to inherit all the class that I want to export to obj to be child of NSobject ? I am getting error 'error: only classes that inherit from NSObject can be declared #objc'
When I export a swift class with #objc, I need to add #objc to all its parent classes, protocol and interface and also class and structure in all its methods, is that correct?
No. Objective-C cannot see a native Swift struct.
Yes. Objective-C classes must basically be derived from NSObject. Objective-C can be made aware of the existence of other classes, but it cannot do anything useful with them.
You can mark the class with #objcMembers, in which case you will give everything within it full visibility to Objective-C.

Any way to use a plain Swift class in Objective C files?

This question isn't about bridging headers and all that. I've got all that working. My question is specifically about what I need to do to my Swift classes to get them to show up in Obj-C code.
Take, for example, this simple class:
class MyClass {
var value: String = ""
}
If I have this class in my Project, it doesn't get included in the MyProject-Swift.h file that gets auto-generated. My understanding is that in order to use a Swift class in Objective-C, my class needs to derive from a class that Objective-C knows about. This is where I start to doubt the actual requirements.
If my class were derived from a UIViewController, then no problem. But if this is just a model object, then it's not deriving from anything. While it is entirely possible to easily make my class derive from NSObject, and thus, it gets properly imported into the Obj-C code, deriving from NSObject can cause other issues down the road.
So if I don't want to make my class derive from NSObject, what can I do to make it visible to my Obj-C files? Is there a doc I just couldn't find that explains how to do this?
As far as I am aware currently, Only Swift classes that inherit from NSObject can be declared #objc and bridged into an Objective-C project.
Without that conformance/inheritance, you'll end up missing some crucial functionality to Objective-C like message sending.
All of that being said, an Objective-C class has to inherit from a parent class and the default root class is NSObject. You almost definitely want to just inherit and make your class a PONSO.

Accessing Swift Class Public Variable in Objective-C Class Xcode 9

I am trying to access Public variable in Objective-C class declared in swift class. But I am getting "Unknown Method" error. Here is my code for accessing variable:
NSLog(#"job on quick blox : %#",[QuickBloxJobClass jobOnQB]);
and it shows compile error:
No known class method for selector 'jobOnQB'
And here is my code in QuickBloxJobClass:
#objc public class QuickBloxJobClass: NSObject
{
static var jobOnQB: QBCOCustomObject = QBCOCustomObject ()
}
I cannot make it public variable because I have Class methods in QuickBloxJobClass. Even I tried it by creating a variable for QuickBloxJobClass. But the variable was still unaccessible.
It was working working fine in Xcode .
Please suggest me some solution.
I'm not sure why jobOnQB cannot be public, presence of class methods should not interfere with it being public, but if it cannot be public for some reason, you can add a static method to QuickBloxJobClass to get the variable.
BTW, the syntax [QuickBloxJobClass jobOnQB] is for calling a static method jobOnQB on class QuickBloxJobClass (it works, though). Strictly speaking, however, since jobOnQB is a property, a better Objective-C syntax would be QuickBloxJobClass.jobOnQB.
Another observation is that #objc inference is deprecated in Swift 4, so it's a good idea to explicitly mark Swift methods and properties callable from Swift with #objc. In fact, you have to do it if Swift 3 #objc inference is set to Off.
Update: This needs to be further investigated, it may be just a matter of some settings. I get the behavior you described if I add Swift code to a project initially set up as Objective-C, but internal members defined in Swift can be accessed just fine in Objective-C if the project is initially set up in Swift with Objective-C files added later. Again, if Swift 3 #objc inference is disabled, you still have to mark such members with #objc.
Update 2: This access problem can be resolved in a project initially set up in Objective-C by adding a bridging header. Then internal Swift members become visible in Objective-C, even though the purpose of a bridging header is the opposite: make Objective-C stuff visible in Swift.

Objective-C call Swift function

Swift function defined in MySwift.swift File:
func SomeSwift()
{
}
SomeSwift() is not defined in any Swift class, it is just a pure function.
After CMD + B to build the project, open Project-Swift.h, the SomeSwift() isn't show in there.
Does the function in Swift have to be defined in some Swift class? and with #objc marked?
like the following:
#objc class SomeSwift: NSObject {
func SomeSwift()
{
}
}
Referring to Apple Documentation about Using Swift from Objective-C:
A Swift class must be a descendant of an Objective-C class to be
accessible and usable in Objective-C
Means that your class should be #objc class SomeSwift: NSObject (You're right!), but you CANNOT access the whole thing in Swift file:
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. This excludes Swift-only features, such as
those listed here:
Generics
Tuples
Enumerations defined in Swift without Int raw value type
Structures defined in Swift
Top-level functions defined in Swift
Global variables defined in Swift
Typealiases defined in Swift
Swift-style variadics
Nested types
Curried functions
Reference.
So, you cannot use the SomeSwift top-level function.
Even if you tried to add #objc before its declaration, the compiler will tell that:
#objc can only used when with memebers of classes, #objc protocols,
and concrete extensions of classes.
with a suggestion to remove #objc.

Is it possible for Swift to inherit from an lightweight generic Objective-c Class?

I have two classes, the base class is in Obj-c and the subclass is in Swift.
The Obj-c class uses new XCode 7's lightweight generic feature defined as follows:
#interface BaseController<T: SFObject *> : UIViewController
#property(nonatomic, strong) T model;
#end
That works fine for Obj-c subclasses.
Now for Swift if I define the generic type as I usually do I get the following error:
Cannot specialize non-generic type 'BaseObjcController'.
My second class is defined as follows:
class SwiftController: BaseObjcController<SFUser> {
}
Any help would be appreciated.
Thanks.
Update: As of Swift 3, Objective-C lightweight generics are imported into Swift. For more information, see
SE-0057 Importing Objective-C Lightweight Generics
Using Imported Lightweight Generics in Swift
Old answer: From Interacting with Objective-C APIs:
NOTE
Aside from these Foundation collection classes, Objective-C
lightweight generics are ignored by Swift. Any other types using
lightweight generics are imported into Swift as if they were
unparameterized.
So this is not possible at present. As you can see from the
"Generated Interface" assistant view, your Objective-C class is imported
to Swift as
public class BaseController : UIViewController {
public var model: SFObject!
}
This was also discussed in the Apple Developer Forum:
Objective-C generics not visible from Swift?
Feel free to file an enhancement bug report!

Resources