Swift and Objective-C Classes With the Same Name - objective-c

I am still learning how to integrate Swift code into code written in Objective C. Let's say if I name the Swift file and class the same name which already was taken by any class of Objective-C. For example,
I would create: "ViewController.swift", and have the following content:
import Foundation
import UIKit
#objc class ViewController:UIViewController {
func swiftMethod() {
print("It works.")
}
}
There are already "ViewController.h" and "ViewController.m". And later I would try to call the Swift class in Objective-C:
#import <myproject-Swift.h>
...
ViewController *vc = [ViewController new];
[vc swiftMethod];
...
How the compiler would know which class I initiated: the class from Swift or from Objective-C?

In the Obj-C runtime, the two classes actually have different names. The Swift class is named YourProject.ViewController while the Obj-C class is named simply ViewController.
From Obj-C code, which class you get will depend on which header you import.
If you import both headers then it's a compiler error.
If you force both classes to have the same name, using:
#objc(ViewController) class ViewController: UIViewController {
}
then it's a linker error.

Related

Unable to call some methods from an Objective-C class in a Swift extension of that class

I have an objective-c class something like:
#interface MyClass: NSObject { }
- (MyObject *)coolMethod;
#end
#implementation MyClass
- (MyObject *)coolMethod {
return [self doCoolStuff];
}
#end
...and a Swift extension something like:
extension MyClass {
#objc func addedMethodInSwift() {
let coolObj = coolMethod() // <<<< compiler error - method not found
}
}
The code will not compile, because the compiler cannot find the implementation of coolMethod(), however certain other methods from the Objective-C class can be called from the Swift extension.
I have checked and the Objective-C header file is included in the project's bridging header, so it should be visible to Swift. The method in question is definitely visible in the header file.
Why can't coolMethod() be called from the Swift extension?
Check that both your objective-C class and the return type of the function (in your case MyObject.h) are included in the Bridging header. Methods with return types not included in the bridging header are not available from Swift.

how to exclude classes from <MyProject>-swift.h

I have a project that was started in Objective-C, and I am trying to import some Swift code into the same class files that I have previously written Objective-C in.
I need exclude Swift classes from <MyProject>-swift.h
for example exclude LoginVC
Only the swift class with #objc will generate objective-c interface in Project-swift.h.
By adding #objc, your swift class will be visible by others objective-c class.
Example :
#objc class LoginVC : UIViewController{ //will be present in Project-swift.h
class LoginVC : UIViewController{ //will not be present in Project-swift.h

Can Objective-C code call Swift class extensions?

I searched some posts, I think I cannot write an extension under Swift, and call it from Objective-C code, right?
#objc like attributes only support methods, class, protocols ?
You can write a Swift extension and use it in Objective-C code. Tested with Xcode 6.1.1.
All you need to do is:
create your extension in Swift (#objc annotation needed since Swift 4.0.3)
#import "ProjectTarget-Swift.h" in your Objective-C class (where "ProjectTarget" represents the XCode target the Swift extension is associated with)
call the methods from the Swift extension
I found out that in Swift 4.0 I had to add #objc in front of my extension keyword in order for the Swift extension methods to become visible by an instance of the Objc class I was extending.
In short:
File configuration setup:
CustomClass.h
CustomClass.m
CustomClassExtension.swift
In CustomClassExtension:
#objc extension CustomClass
{
func method1()
{
...
}
}
In my AppDelegate.m:
self.customClass = [[CustomClass alloc] init];
[self.customClass method1];
This solution works for Swift 2.2 and Swift 3. Note that only extensions for classes (not for structs or enums) will be accessible from Objective-C.
import UIKit
extension UIColor {
//Custom colours
class func otherEventColor() -> UIColor {
return UIColor(red:0.525, green:0.49, blue:0.929, alpha:1)
}
}
Then #import "ProductModuleName-Swift.h" in your ObjC file.
Swift 4
extension UIColor {
// As of Swift 4.0.3, the #objc annotation is needed if you want to use the extension in Objective-C files
#objc
class func otherEventColor() -> UIColor {
return UIColor(red:0.525, green:0.49, blue:0.929, alpha:1)
}
}
As covered in the other answers, importing the generated Swift header works in most cases.
An exception to this is when the category is defined on a bridged type (i.e. the extension is defined on String and not NSString). These categories will not automatically be bridged to their Objective-C counterparts. To get around this, you'll either need to use the Objective-C type (and cast the return value in your Swift code with as String) or define an extension for both the Swift and Objective-C types.
Import "#import "ProductModuleName-Swift.h" header in objective-c file and add #objc infront of your extentsion in swift file. It will working fine in swift 4.2 and swift 5
If think you have configured everything correctly (marked your Swift entities with #objcMembers or #objc, imported the bridging header "ProductModuleName-Swift.h" and so on) – but still getting the No visible #interface for 'FooClass' declares the selector 'fooSelector' error:
Check if you see your interfaces in the bridging header by ctrl + cmd clicking on it. If you don't, check out my answer to this question: Swift to Objective-C header does not contain Swift classes

"ProductModuleName-Swift.h" not exporting all Swift classes

I have defined two Swift classes in my Xcode project. Everything else is Objective-C.
To use the classes in Objective-C I'm trying to import ProductModuleName-Swift.h but the file contains only the definition for one of the Swift classes. (SearchViewController)
This class is being exported:
class SearchViewController : UIViewController {
but this isn't:
public class Socket {
From "Migrating Your Objective-C Code to Swift" in the "Using Swift with Cocoa and Objective-C" documentation:
To be accessible and usable in Objective-C, a Swift class must be a descendant of an Objective-C class or it must be marked #objc.
When you bring Swift code into Objective-C, remember that Objective-C won’t be able to translate certain features that are
specific to Swift. For a list, see "Using Swift from
Objective-C".
SearchViewController is a descendent of an Objective-C class, but Socket is not.
To make it usable in Objective-C, declare it as a subclass of NSObject:
public class Socket : NSObject { ...
or declare it as
#objc public class Socket { ...

How to declare a constant in swift that can be used in objective c

if I declare the swift constant as a global constant like:
let a = "123"
but the a cannot be found in objective c.
How to solve this?
From Apple Doc:
You’ll have access to anything within a class or protocol that’s marked with the #objc attribute as long as it’s compatible with Objective-C. This excludes Swift-only features such as those listed here:
Generics
Tuples
Enumerations defined in Swift
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
Therefore its not possible to access global variables(Constants) or global functions defined in Swift.
Possible Solutions:
From the Apple Document Swift programming language, You can Declare Type Properties as
class var constant: Int = {
return 10
}()
But currently in Swift(beta-3) Type properties are not supported.
You can declare a Class function to get a constant value:
In Swift:
class func myConst() -> String {
return "Your constant"
}
Accessing from Objective-C:
NSString *constantValue = [ClassName myConst];
NSLog(#"%#", constantValue);
Swift code:
public class MyClass: NSObject {
public static let myConst = "aConst"
}
and then in Objective-C:
[MyClass myConst]
Isn't this working as well? As in this works for me.
Also this is somewhat shorter as creating a object first (alloc, init). Making a new function for every constant is... not pretty :/
Update for Swift 4
Because of the changes in Swift 4's Objective-C inference, you need to add the #objc annotation to the declared constant as well. The previous declaration then becomes:
#objcMembers
public class MyClass: NSObject {
public static let myConst = "aConst"
}
The calling Objective-C code remains the same.
Using #objcMembers makes all constants available (as if you'd write #objc before each constant), but I've had times where the compiler somehow wouldn't generate the corresponding ObjC code.
In those cases I'd suggest adding the #objc decorator before the constant as well.
I.e.: #objc public static let myConst = "aConst"
You should not have any problem by using let in Objective-C, next example was made with Xcode 7.2 :
MyClass.swift
import Foundation
import UIKit
#objc class MyClass : NSObject { // <== #objc AND NSObject ARE BOTH NECESSARY!!!
let my_color = UIColor( red:128/255,green:32/255,blue:64/255,alpha:1 ) // <== CONSTANT!!!
}
MyObjectiveC.m
#import "PROJECTNAME-Swift.h" // <== NECESSARY TO RECOGNIZE SWIFT CLASSES!!!
#interface MyObjectiveC ()
#end
#implementation MyObjectiveC
#synthesize tableview; // <== ANY UI OBJECT, JUST AS EXAMPLE!!!
- (void) viewDidLoad () {
MyClass * mc = [ [ MyClass alloc ] init ]; // <== INSTANTIATE SWIFT CLASS!!!
tableview.backgroundColor = mc.my_color; // <== USE THE CONSTANT!!!
}
#end
PROJECTNAME is the name of your Xcode project, as shown in Project Navigator.
In your swift class,
let constant: Float = -1
class YourClass: NSObject {
class func getMyConstant() -> Float {return constant}
...
}
Clean, build to let xcode prepare this method useable for obj-c.
Then at your obj-c class
if ([YourClass getMyConstant] != 0) {
...
}
First of all you need to know about the important of auto-generated Swift header file.
It is the one that will made the magic to transcribe the Swift code to be understandable from Objective-C.
This file is auto-generated by Xcode (do not look for it in your project).
The important of this file is to use the correct name, it can match with your target name, but, may not, it is the product module name. (Search for it in your project settings as "Product module")
You need to import this file on the Objective-C class that you want to use a Swift class and also the Swift class name of your Swift file.
#import <ProductModuleName-Swift.h>
#class MySwiftClassName;
My Swift class should have the prefix #objc and inherit from NSObject:
#objc class MySwiftClassName: NSObject {
let mySwiftVar = "123"
}
Then you can call your Swift variable from the Objective-C file:
MySwiftClassName *mySwiftClassO = [[MySwiftClassName alloc] init];
NSString *myVar = mySwiftClassO.mySwiftVar;
Make sure to clean and rebuild your project after each change to force regenerate this auto-generated file.
If your Swift header file was auto-generated correctly you can navigate to it by clicking over the import file name and check if all the code you need was properly transcribed.
In the following post you can find more detailed information about this. https://solidgeargroup.com/bridging-swift-objective-c
Classes func don't work. The only solution I have found out is this one:
class YourController: NSObject {
#objc static let shared = YourController()
private override init() { }
#objc class func sharedInstance() -> YourController {
return YourController.shared
}
#objc let terms = "Your-String-here"
And then on Obj-c file:
[[YourController sharedInstance].terms]