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

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.

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.

Unable to access to Swift 4.2 class included in a framework into Objective C Project

I've got a framework built in both Objective C and Swift. I've upgraded it from Swift 3 to Swift 4.2, and now, after exporting it through Aggregate target and importing the generated framework inside my Objective C demo app, it doesn't show me any Swift class.
I've already checked if -swift.h is correctly builded, and I can see inside it all Swift classes. However, even if I import the umbrella header inside my demo app, I can't see them.
Thanks
By default Swift generates code that is only available to other Swift code, but if you need to interact with the Objective-C runtime – all of UIKit, for example – you need to tell Swift what to do.
That’s where the #objc attribute comes in: when you apply it to a class or method it instructs Swift to make those things available to Objective-C as well as Swift code. So, any time you want to call a method from a UIBarButtonItem or a Timer, you’ll need to mark that method using #objc so it’s exposed – both of those, and many others, are Objective-C code.
class MyController: UIViewController {
#objc func authenticateUser() {
}
To make this class accessible from Objective-C, we need to add the #objc keyword just before the class declaration. This tells the compiler to do some magic behind the scenes (namely, create an invisible header file)
#objc class SwiftViewController: UIViewController {
// ...
}
Reference - https://www.hackingwithswift.com/example-code/language/what-is-the-objc-attribute

When #objc and #nonobjc write before method and variable in swift?

When I declare static parameter in extension of class then I have to write #nonobjc before variable like:
#nonobjc static let test = "test"
and sometimes I have to write #objc before method, so what is use of #objc and #nonobjc in Swift.
Can anyone help me for this problem?
This is explained in the Apple's official documentation about Objective-C - Swift interoperability:
When you use the #objc(name) attribute on a Swift class, the class is
made available in Objective-C without any namespacing. As a result,
this attribute can also be useful when migrating an archivable
Objective-C class to Swift. Because archived objects store the name of
their class in the archive, you should use the #objc(name) attribute
to specify the same name as your Objective-C class so that older
archives can be unarchived by your new Swift class.
Conversely, Swift also provides the #nonobjc attribute, which makes a
Swift declaration unavailable in Objective-C. You can use it to
resolve circularity for bridging methods and to allow overloading of
methods for classes imported by Objective-C. If an Objective-C method
is overridden by a Swift method that cannot be represented in
Objective-C, such as by specifying a parameter to be a variable, that
method must be marked #nonobjc.
To summarize, use #objc when you want to expose a Swift attribute to Objective-C without a namespace . Use #nonobjc if you want to keep the attribute available and accessible only in Swift code.
(Addendum/additional official details to #bontoJR well summarizing answer)
From the Swift Language Reference - Attributes [emphasis mine]:
objc
Apply this attribute to any declaration that can be represented in
Objective-C — for example, non-nested classes, protocols, nongeneric
enumerations (constrained to integer raw-value types), properties and
methods (including getters and setters) of classes and protocols,
initializers, deinitializers, and subscripts. The objc attribute tells
the compiler that a declaration is available to use in Objective-C
code.
...
nonobjc
Apply this attribute to a method, property, subscript, or initializer
declaration to suppress an implicit objc attribute. The nonobjc
attribute tells the compiler to make the declaration unavailable in
Objective-C code, even though it is possible to represent it in
Objective-C.
...
Here you can find more details in this Swift Documentation : InteractingWithObjective-C
As an answer of your question, overview from attached link is as below.
#objc : You can use attribute to change the name of a class, property, method, enumeration type, or enumeration case declaration in
your interface as it’s exposed to Objective-C code.
Example : if the name of your Swift class contains a character that isn’t supported by Objective-C, you can provide an alternative name to use in Objective-C.
#nonobjc : It makes a swift declaration unavailable in Objective-C. You can use it to resolve circularity for bridging
methods and to allow overloading of methods for classes imported by
Objective-C.

#objc error when migrated to Swift 2

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.

Lazy init to variables in an #objc class in Swift

I am trying to use lazy initialization for instance for an Array in a class in Swift.
When i am using #objc declaration for the class, in order to use it in objective-c i got a compilation error. When i just use the class without #objc, i can compile it without any issues.
I get errors for this:
#objc class MyClass {
#lazy var arr : String[] = String[]()
}
For the following code, i get no errors:
class MyClass {
#lazy var arr : String[] = String[]()
}
Thank you your help!
In the first case I think its a bug in bridge code generator Developer forum.
If anything which is not objective-C compatible compiler won't
generate it's objective-C equivalent (it won't give Error), For
example if you have a Generics or tuple that are not supported in
objective-C compiler is not going to generate objective-C equivalent
for this also it won't give error.
In the second case you are not including #objc , From apple doc :
A Swift class or protocol must be marked with the #objc attribute to
be accessible and usable in Objective-C. This attribute tells the
compiler that this piece of Swift code can be accessed from
Objective-C.If your Swift class is a descendant of an Objective-C class, the compiler automatically adds the #objc attribute for you.
Hence this class is not included(not accessible) , so its not giving error.

Resources