Create iOS framework using swift - ios

I am trying to create an iOS framework using swift. I follow this blog and also few others but the output is not the way I want.
Below is my original source file
public class TestClass: NSObject {
// publicVar description
public var publicVar: Int = 0
// doSomething description
public func doSomething() {
print("doSomething method")
}
}
After adding the framework into my project it's create an TestFramwork-Swift.h
You can see it's not contain my description. I want the framework
header files like Apple.
Can anyone help me to figure out this. I am not able to understand where I am doing wrong. I am also not able to add more swift files into my framework.

Just use triple slash instead of double slash for comments you want to show in your framework headers.

Related

{Module_name}-Swift.h file not working well only in Swift 4 projects unlike Swift 3.2

Anyone faced problems in {Module_name}-Swift.h file for Swift 4 projects? I've noticed -Swift.h autogenerated file not working well with Swift 4 syntax unlike Swift 3.2!.
For example, -Swift.h file doesn't contain all variables and methods which implemented in the custom Swift classes which inherited from NSObject class!
I've used #objc and #classkeywords but no way.
I don't get any errors! the problem is if I've created a class like this:
import Foundation
class Utils: NSObject {
let abc: String?
func xyz() {
print("")
}
}
and navigate to {Module_name}-Swift.h I see something like that:
SWIFT_CLASS("_TtC3{Module_name}5Utils")
#interface Utils : NSObject
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
#end
Problem
Both let abc: String? and func xyz() have been never included in {Modue_name}-Swift.hfile!
I think in Swift 4 you have to mark a lot more things #objc (nothing implicit anymore) but other than that it should just be in there.
You can all check it to confirm class name in .h file like:
#class filename;
The generated file {Module}-Swift.h does not contain your variables and methods, the file is generated to give you access to the Module namespace.
The actual interface for the generated module lives in Module.swiftmodule/arm64.swiftmodule (depending on built architecture).
More information on its contents:
https://bugs.swift.org/browse/SR-2502
https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20160111/000827.html
https://stackoverflow.com/a/24396175/1755720
however... the format is not documented anywhere and is subject to change. A good starting point would be to look in include/swift/Serialization/ModuleFormat.h
As to why it's not working - Swift 4 has a migration process, please ensure you have followed it: https://swift.org/migration-guide-swift4/
Xcode will pick up most things ... but it won't get everything!
And why do you need header files for Swift classes? You just can mark swift class as #objc and you will be able to reach all its properties.

Swift: import framework but can't find class in it

I import a swift framework to a swift project, but when I call the class in this framework, Xcode throw a compile error "Use of undeclared type 'xxxx(class name)' ".
I feel Xcode have found the framework, otherwise it will complaint "can't find xxx(framework name)".
But why Xcode can't find the class of this framework.
I have tried remove and re-add framework, and delete DeivedData files, but all of them not work. I haven't use CocoaPods to import framework.
Any idea?
In a Framework that was built for Release (and not Debug), the class symbols need to be accessible.
Make sure you are you trying to access Public or Open classes from your Swift framework.
// set the Framework class to Public
public class rnHello{
// set the initializer to public, otherwise you cannot invoke class
public init() {
}
// set the function to public, as it defaults to internal
public static func world() {
print("hello from a static method")
}
}
Now you can access this via your Swift code or if you attach lldb using:
lldb) po rnHello.world()
Make sure that the FrameWorkSearch path in the BuildSettings of the project is reflecting the correct path to your framework.

How to import Objective-C in Swift framework

i create a swift framework, and create a objectivC file in the framework project.
swiftClass.swift:
Public swiftClass{
func test(){
var c = objectivCClass();
}
}
objectivCClass.h:
#Interface objectivCClass{
}
#end
I know make objectivCClass.h to public header in Build Phases , and import it in swiftFramework.h , the framework can works ok.
But I do not make objectivCClass public in Build Phases and do not want user knows the class. If I make objectivCClass.h to project/private header , An error happen.
Who know how to handle it?

Compile and runtime failures when importing interfaces with category extensions in XCode 7

I'm trying to get an example of running OpenEars with the RapidEars plugin running in Swift 2.2 (XCode 7.3.1). However, I suspect I'm having a larger issue with using Objective-C interfaces with extensions in a Swift project (or my understanding of how that works).
The OpenEars code is Obj-C. However I was able to get it running in my swift project through the standard Obj-C -> Swift translation techniques.
Abbreviated code follows. The full example is on a forked Github and updated to Swift-2.2: https://github.com/SuperTango/OpenEars-with-Swift-
This following example is working great. You can see the entire project by checkng out the "working-opears-swift2.2" tag.
OpenEarsTest-Bridging-Header.h:
#import <OpenEars/OELanguageModelGenerator.h>
#import <OpenEars/OEAcousticModel.h>
#import <OpenEars/OEPocketsphinxController.h>
#import <OpenEars/OEAcousticModel.h>
#import <OpenEars/OEEventsObserver.h>
ViewController.swift:
class ViewController: UIViewController, OEEventsObserverDelegate {
var openEarsEventsObserver = OEEventsObserver()
override func viewDidLoad() {
super.viewDidLoad()
loadOpenEars()
}
func loadOpenEars() {
self.openEarsEventsObserver = OEEventsObserver()
self.openEarsEventsObserver.delegate = self
var lmGenerator: OELanguageModelGenerator = OELanguageModelGenerator()
addWords()
var name = "LanguageModelFileStarSaver"
lmGenerator.generateLanguageModelFromArray(words, withFilesNamed: name, forAcousticModelAtPath: OEAcousticModel.pathToModel("AcousticModelEnglish"))
lmPath = lmGenerator.pathToSuccessfullyGeneratedLanguageModelWithRequestedName(name)
dicPath = lmGenerator.pathToSuccessfullyGeneratedDictionaryWithRequestedName(name)
}
func startListening() {
do {
try OEPocketsphinxController.sharedInstance().setActive(true)
OEPocketsphinxController.sharedInstance().startListeningWithLanguageModelAtPath(lmPath, dictionaryAtPath: dicPath, acousticModelAtPath: OEAcousticModel.pathToModel("AcousticModelEnglish"), languageModelIsJSGF: false)
} catch {
NSLog("Error!")
}
}
// A whole bunch more OEEventsObserverDelegate methods that are all working fine...
func pocketsphinxDidStartListening() {
print("Pocketsphinx is now listening.")
statusTextView.text = "Pocketsphinx is now listening."
}
Up until this point, everything is working great.
However, In order to use the "RapidEars" plugin, the documentation (http://www.politepix.com/rapidears/) says to:
Add the framework to the project and ensure it's being included properly.
import two new files (that are both "categories" to existing OpenEars classes):
#import <RapidEarsDemo/OEEventsObserver+RapidEars.h>
#import <RapidEarsDemo/OEPocketsphinxController+RapidEars.h>
Change methods that used: startListeningWithLanguageModelAtPath to use startRealtimeListeningWithLanguageModelAtPath
add two new OEEventsObservableDelegate methods.
func rapidEarsDidReceiveLiveSpeechHypothesis(hypothesis: String!, recognitionScore: String!)
func rapidEarsDidReceiveFinishedSpeechHypothesis(hypothesis: String!, recognitionScore: String!)
The new code can be found by checking out the rapidears-notworking-stackoverflow tag from the above github repo
Problem 1:
When doing completion in the XCode editor, the editor sees WILL perform autocompletion on the startRealtimeListeningWithLanguageModelAtPath method, however when the code is run, it always fails with the error:
[OEPocketsphinxController startRealtimeListeningWithLanguageModelAtPath:dictionaryAtPath:acousticModelAtPath:]: unrecognized selector sent to instance 0x7fa27a7310e0
Problem 2:
When doing auto completion in the XCode editor, it doesn't see the two new delegate methods defined in RapidEarsDemo/OEPocketsphinxController+RapidEars.h.
I have a feeling that these are related, and also related to the fact that they failing methods are defined as Categories to Objective-C classes. But that's only a guess at this point.
I've made sure that the RapidEars framework is imported and in the framework search path.
Can anyone tell me why this is happening? Or if there's some Swift magic incantation that I missed?
The problem could be the one described in the link below, where category methods in a static library produce selector not recognized runtime errors.
Technical Q&A QA1490: Building Objective-C static libraries with categories

I want to call a class function written in Swift from the AppDelegate (which is in Objective C). What am I doing wrong?

I have a swift file "SomeController.swift" it is like this:
import Foundation
func performSomeStuff() {
println("Performing stuff")
}
Now in the app delegate, I am trying to do this: (note that the swift bridging header is imported)
[SomeController performSomeStuff]
But its not working.
I have also tried this:
import Foundation
class SomeController:NSObject {
class func performSomeStuff() {
println("Performing stuff")
}
}
But it still fails.
What is the correct way?
Add:
#objc
before the class keyword in your swift code so it will be:
#objc class SomeStuff: NSObject {
}
Also add #obj in front of any function that you want to call.
Then in your app delegate make sure to use #import "projectName-Swift.h"
Are you able to access "SomeController" class in objective-c, if not then you firstly need to add "${ProjectName}-Swift.h file and add Swift compilation support in Build settings as:
And for accessing methods from Swift to Objective-C, add
import Foundation
class SomeStuff:NSObject {
#objc class func performSomeStuff() {
println("Performing stuff")
}
}
before functions name.
In some cases, you need finer grained control over how your Swift API is exposed to Objective-C. You can use the #objc attribute if your Swift class doesn’t inherit from an Objective-C class, or if you want to change the name of a symbol in your interface as it’s exposed to Objective-C code.
https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html
Ok, So I figured it out. First, here's the correct way. Its like some of you said:
In the swift file, I have it like this:
class MyController:NSObject{
class func performTask {
// Here my task is running.
}
}
Then in the app delegate, I just import the swift header file. And do this:
[MyController performTask];
Now for the part I had wrong. It was an error on my part, but maybe it'll be useful to someone else out there.
When I first created the first swift file, I had placed it inside a folder within the my Source folder. But when I started having multiple swift files, I moved the bridging header outside that folder and into the main Source folder (just for organising).
The problem was, it did not give me a direct error to tell me what was the problem. I had to check the issue navigator to identify the problem.
Hope this helps someone out there.

Resources