Swift class in Objective C Project - objective-c

I'm having problems executing some Swift code in an existing ObjC project. This is my first attempt at Swift so I'm sure I'm missing something simple.
I have added my new swift file to my project - this process generated the bridging header. So now I have the following:
bridging-header file
//
// Use this file to import your target's public headers
// that you would like to expose to Swift.
//
#import "historyViewController.h"
In my swift file I have the following test class and function:
import Foundation
#objc class Hello: NSObject {
func sayHello() {
print("Hi There")
}
}
In my historyViewController.m file I have the following
#import "xx-Bridging-Header.h"
In my historyViewController.h file I have the following
#class Hello;
How do I actually go about executing the sayHello function from within my historyViewController.m file? I've tried [Hello sayHello]; - but get 'no known class method'.

The problem is only that you are calling sayHello as if it were a class method, but sayHello is declared as an instance method. So:
[[Hello new] sayHello];

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.

Writing Swift 2.0 code inside Objc *.m file

I'm trying to use a swift classes methods from my objective-c .m file but I can't get my file to import.
In Build Settings -> Packaging I have: Defines Module YES
my Product Module Name is Library
In Build Options I have set Embedded Content Contains Swift Code as YES
However, when I attempt to import the target module to my *.m file I get file not found error.
#import "Library-Swift.h"
Fails to import.
I have swift files. Any ideas?
I'm also trying to use `"Library-Bridging-Header.h"
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "PLAddBookViewController.h"
..but it doesn't seem to be doing anything.
You can expose your Swift class to ObjC in 2 ways:
class MySwiftClass : NSObject { // inherit from any ObjC class
}
#objc class MyClassClass { // tell the compiler to expose it to ObjC
}
From the Swift book:
When you define a Swift class that inherits from NSObject or any other Objective-C class, the class is automatically compatible with Objective-C. If your Swift class does not derive from an Objective-C class and you want to use an API from that class in Objective-C code, you can use the #objc attribute described below.
The #objc attribute makes your Swift API available in Objective-C and the Objective-C runtime. In other words, you can use the #objc attribute before a Swift method, property, subscript, initializer, class, protocol, or enumeration to use it from Objective-C code.

Swift and Objective-C Classes With the Same Name

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.

objective-c - Swift classes are not visible in Objective-C .h file

I'm trying to use Swift class in my Objective-C file.
I included "moduleName-Swift.h" file in my SuperViewController.m file, but when I try to declare a public method in SuperViewController.h with Swift-class as method parameter, I obviously get an error: "Expected a type"
How can I use swift-class in a header file if I can only include projectModule-Swift.h in .m files??
Make sure to put #objc before the swift class name.
#objc myclassname { ... }
Also add
#class myclassname;
in your obj-c header file where you want to access the swift class
Remember to import the project generated swift header file in your source file, for example #import <MyProjectName-Swift.h>
I had the same problem. Adding #class MyClassName in obj-c .h file created the "Receiver 'MyClassName' for class message is a forward declaration" error, so I deleted that and ONLY added the "#objc" before the swift class name, BUT I also had to make sure that the swift class is a subclass of NSObject.
#objc class MySwiftClass:NSObject { ... }
WITHOUT #class MyClassName in obj-c .h file!
I had to use:
#obj public class MySwiftClass: NSObject { ... }
I created a class with no subclass, adding #objc and #objcmembers did not work.
After I change do :NSObject the entire class turn visible to objective-C

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]