Swift Class can not be reached in Objective-C class? - ios

I have a model class written in Swift and a backend service controller written in Objective-C.
Let's say the file names are SomeModel.swift and SomeRequestController.m and it's header.
I don't want to import the ProjectName-Swift.h inside the header file. So I have used forward declaration inside the header file. I import ProjectName-Swift.h inside SomeRequestController.m file.
The Swift file looks like following:
import Foundation
#objc class SomeModel: NSObject {
#objc var prop1: String?
#objc var prop2: String?
#objc var prop3: String?
}
I can reach this model class in objective-c in the other parts of the code. Forward declaration makes enable to create an object inside the code. So Xcode finds the class. However when I compile it fails with the message:
Property 'prop1' not found on object of type '__strong id'
How can I solve this without changing the import mechanism?

I have solved the problem. Here, I would like to introduce this specific case for those who may encounter with such a problem in the future.
The objective-c file is in target membership with two projects. The Swift file was in target membership with one of them. I have assigned this Swift file to the second project. It compiles now.

Related

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.

Class prefixes in project with both objective-c and swift

I'm aware that we no longer need to prefix class names in swift. But I'm working on a project containing both swift and Objective-c.
Should I prefix the swift class names of keep them the "swift way"?
You can go ahead and keep it the Swift way. If you're worried about name-clashes and adding a prefix, you can change the Objective-C class name by adding #objc(...) before the class declaration.
E.g.
#objc(XXMyClass) class MyClass: ... {
...
}

Import ViewController.swift in Objective C file

I'm trying to use my new ViewController.swift file in my existing objective C project.
Below is swift file code
import UIKit
class TutorialViewController: UIViewController{
}
Below is Objective C code
#import "TutorialViewController-Swift.h" //"TutorialViewController-Swift.h" file not found
I'm unable to import swift code. I had followed all the steps in this
Please let me know, where am I making mistake. Is it only applicable for NSObject class.
Thanks in advance
You can't import a swift class directly to Objective C class like that way. By default Xcode generates a swift bridging header for this purpose. You need to import that header. Normally that header file uses the following naming convention:
<#your module name #>-Swift.h
Or you can get the value from your target's build settings:
Choose your target
Go to Build Settings tab
Go to Swift Compiler - Code Generation category
Check the value of Objective-C Generated Interface Header Name
Import that header in your objective-c class to use all your swift classes
As per document, When you import Swift code into Objective-C, you rely on an Xcode-generated header file to expose those files to Objective-C. This automatically generated file is an Objective-C header that declares the Swift interfaces in your target. It can be thought of as an umbrella header for your Swift code. The name of this header is your product module name followed by adding "-Swift.h".
By default, the generated header contains interfaces for Swift declarations marked with the public modifier. It also contains those marked with the internal modifier if your app target has an Objective-C bridging header. Declarations marked with the private modifier do not appear in the generated header. Private declarations are not exposed to Objective-C unless they are explicitly marked with #IBAction, #IBOutlet, or #objc as well. If your app target is compiled with testing enabled, a unit test target can access any declaration with the internal modifier as if they were declared with the public modifier by prepending #testable to the product module import statement.
You don’t need to do anything special to create the generated header file—just import it to use its contents in your Objective-C code. Note that the Swift interfaces in the generated header include references to all of the Objective-C types used in them. If you use your own Objective-C types in your Swift code, make sure to import the Objective-C headers for those types before importing the Swift generated header into the Objective-C .m file you want to access the Swift code from.
For more details follow this Importing Swift into Objective-C

How does swift know which files to import?

I'm diving into swift from the land of Objective-C, and I'm curious about swift's importing functionality. I've discovered that there's no need to import my own classes, like so:
Objective-C:
#import <UIKit/UIKit.h>
#import "CustomObject.h"
CustomObject* newObject = ...
Swift:
import UIKit
//no need to import CustomObject
var newObject: CustomObject...
My question is, how does swift accomplish this? Where does it look for .swift files to automatically import? Is it just any .swift file that's added to your project's target? I don't want to just handwave this and then get caught by surprise later when something doesn't import like magic!
I'm not sure I'm going to explain this with grace but here it goes...
Let's say you're creating an app called Battlefront. When you're adding files/classes to your application, they are in fact added to your app's module, the Battlefront module. Let's say you created a class called Hero, well, your class is not only Hero, it is Battlefront.Hero but since you're using it in the context of the Battlefront module, there is no need to specify the module name when using your class.
Imports in Swift works mostly with modules. I suppose you could import a single class in Swift but I haven't tried it so I can't comment on this. Let's say you're importing CoreData, well you're importing the whole module by using import CoreData.
By default, classes are using the internal access control. If you wanted to expose classes inside Battlefront to be available to other modules, you'd have to specify your class as public:
// Default is internal, not available outside Battlefront
class Hero {
}
// Public class, is available outside Battlefront
public class Weapon {
}
You can read more on Access Control here.
I suppose you could simplify the relationship to Target equals a Module but that would be taking a shortcut. Could be a start of understanding the concept though.
Short answer: yes, Xcode accesses all .swift files in your project.

using custom Swift framework in another Swift project

I am having an issue using a custom pure Swift framework in another project.
Some notes (as I've believe I've thorougly searched for all possible answers) :
I have my classes declared as public in the framework.
I have successfully built and ran the framework with a Swift target application but only from within the framework project.
I have included my framework in Linked Framework and Libraries and Embedded Binaries.
What i am trying to do is build a pure Swift single view application project by importing only the product framework. The error I am getting is "MyClass is unavailable: cannot find Swift declaration for this class" (which as mentioned above is public) . Also I have an public enumaration with a similar error: "Use of undeclared type 'MY_ENUM'"
Example code below:
import Foundation
import UIKit
import MyFramework /// don't know if this is needed.
public class ViewController: UIViewController{
var myclass:MyClass? ///here is the above error ,it's initialized in the viewDidLoad() function
var myEnum:MY_ENUM = MY_ENUM.MY_ENUM_VALUE /// 2nd enumeration error.
override public func viewDidLoad(){
super.viewDidLoad()
self.myClass = MyClass(arguments) ///same error as above
self.myClass?.myFunction /// ViewController does not have a member 'MyClass' error
/// more code here with errors regarding the class and enum.
}
I've also tried using an objective-C Bridging Header (though I believe this is wrong) and importing my framework header.
#import <MyFramework/MyFramework.h>
Is it possible for a solution to the above or is a restriction from Swift and I am trying something in vain?
One final note: I've included some other headers from another Objective-C framework in my framework because it was the only way to build it as a custom Swift framework. The classes there are visible to the Swift application.
P.S.If more code is needed I'll be happy to provide.
Solved the issue.
Had to put the .swift files together with the .h files as public headers in my custom framework (don't understand why though) and build again.
Maybe the path of your framework is wrong?

Resources