Swift Protocol in Framework - ios

so i have this weird problem that's been bugging me for the last few hours.
I have a framework in which I created a protocol named ChatDelegate (code bellow)
public protocol ChatDelegate: class {
func chat(_ chatCollectionView: UICollectionView, didSelect message: Message)
}
and a ViewController (not in the framework), which conforms to the ChatDelegate, like so
extension ChatContainerViewController: ChatDelegate {
func chat(_ chatCollectionView: UICollectionView, didSelect message: Message) {
print("did select")
}
}
but the compiler still complains that the ChatContainerViewController does not conform to the protocol and I don't understand why?? The function has the exact same header (I also tried putting public in front ...didn't help).
Any help would be much appreciated.
UPDATE
I figured it out. The problem was that I had Message class in my project and in the framework and the compiler didn't know which one to choose. Adding ModuleName in front (ModuleName.Message) fixed it. :D

I had the same issue. The file that defined the protocol had a target membership in both the framework and the application targets. I solved the issue by making the file that defined the protocol only have a target membership in the framework and then adding an import <FrameworkName> to the code in the application target that needed to use the protocol.

Related

Implementing Methods from Objective C Library with Swift

I am trying to implement the following method in swift:
From the class FLIROneSDKImageReceiverDelegate, which is subclassed inside my ViewController class as so:
class ViewController: UIViewController, FLIROneSDKImageReceiverDelegate,
FLIROneSDKStreamManagerDelegate,
FLIROneSDKImageEditorDelegate{
Note that I have already created a bridging header etc.
In the FLIROneSDKImageReceiverDelegate header file:
- (void) FLIROneSDKDelegateManager:(FLIROneSDKDelegateManager *)delegateManager didReceiveBlendedMSXRGBA8888Image:(NSData *)msxImage imageSize:(CGSize)size;
Am I wrong in thinking that this is the correct way to implement this function?
func FLIROneSDKDelegateManagerdidReceiveBlendedMSXRGBA8888ImageimageSize(delegateManager: FLIROneSDKDelegateManager!, msxImage: NSData, size: CGSize){
Note that FLIROneSDKDelegateManager is a class.
Off the top of my head, but try this:
func FLIROneSDKDelegateManager(delegateManager: FLIROneSDKDelegateManager!, didReceiveBlendedMSXRGBA8888Image msxImage: NSData!, imageSize size: CGSize) {
// method imp
}
#Laxsnor's solution in the comments on the answer by #aaron-wojnowski helped me too, thanks both.
To consolidate:
The problem is a conflict created by the name FLIROneSDKDelegateManager being used as a both a class name and a function name - which seems to be OK in Objective-C but not in Swift.
Replacing the class FLIROneSDKDelegateManager with NSObject in the function parameter seems to solve the problem without side-effects. This has to be done in both the Objective-C protocol header file and the Swift delegate class source file.
NOTE I also found this same solution applied more broadly to Swift-ify the entire FLIROneSDK at https://github.com/jruhym/flirmebaby.
Happy developing for FLIROne on Swift. (I'm new to FLIROne and relatively new to Swift so apologies if my language isn't quite precise enough.)

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.

'Use of Unresolved Identifier' in Swift

So I have been making an app, and everything has been working great. But today I made a new class like usual and for some reason in this class I can't access Public/Global variable from other classes. All the other classes can, but now when ever I try to make a new class I can't. How would this be fixed?
I am using Swift and Xcode 6.
Working Class:
import UIKit
import Foundation
import Parse
import CoreData
var signedIn = true
class ViewController: UIViewController {
New Class:
import UIKit
class NewClass: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
signedIn = false
}
But on signedIn = false
I get the error:
use of unresolved identifier "signedIn"
One possible issue is that your new class has a different Target or different Targets from the other one.
For example, it might have a testing target while the other one doesn't. For this specific case, you have to include all of your classes in the testing target or none of them.
Once I had this problem after renaming a file. I renamed the file from within Xcode, but afterwards Xcode couldn't find the function in the file. Even a clean rebuild didn't fix the problem, but closing and then re-opening the project got the build to work.
'Use of Unresolved Identifier' in Swift my also happen when you forgot to import a library. For example I have the error:
In which I forgot the UIKit
import UIKit
Sometimes the compiler gets confused about the syntax in your class. This happens a lot if you paste in source from somewhere else.
Try reducing the "unresolved" source file down to the bare minimum, cleaning and building. Once it builds successfully add all the complexity back to your class.
This has made it go away for me when re-starting Xcode did not work.
Another place I've seen this error is when your project has multiple targets AND multiple bridging headers. If it's a shared class, make sure you add the resource to all bridging headers.
A good tip to is to look in the left Issue Navigator panel; the root object will show the target that is issuing the complaint.
For me this error happened because I was trying to call a nested function. Only thing I had to do to have it fixed was to bring the function out to a scope where it was visible.
In my case, I had an Object-C file which was also in the same Target Membership. I fixed by adding #import "YourObjectCFileHeader.h" inside file Bridging-Header.h
Because you haven't declared it. If you want to use a variable of another class you must use
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var DestViewController : ViewController = segue.destinationViewController as ViewController
DestViewController.signedIn = false
}
You have to put this code at the end of the NewClass code
Your NewClass inherits from UIViewController. You declared signedIn in ViewController. If you want NewClass to be able to identify that variable it will have to be declared in a class that your NewClass inherits from.
I got this error for Mantle Framework in my Objective-Swift Project.
What i tried is ,
Check if import is there in Bridging-Header.h file
Change the Target Membership for Framework in Mantle.h file as shown in below screenshot.
Toggle between Private Membership first build the project , end up with errors.
Then build the project with Public Membership for all the frameworks appeared for Mantle.h file, you must get success.
It is just a bug of building with multiple framework in Objective-C Swift project.
If this is regarding a class you created, be sure that the class is not nested.
F.e
A.swift
class A {
class ARelated {
}
}
calling var b = ARelated() will give 'Use of unresolved identifier: ARelated'.
You can either:
1) separate the classes if wanted on the same file:
A.swift
class A {
}
class ARelated {
}
2) Maintain your same structure and use the enclosing class to get to the subclass:
var b = A.ARelated
I did a stupid mistake. I forgot to mention the class as public or open while updating code in cocoapod workspace.
Please do check whether accesor if working in separate workspace.
You forgot to declare the variable. Just put var in front of signedIn = false
My issue was calling my program with the same name as one of its cocoapods. It caused a conflict. Solution: Create a program different name.
This is not directly to your code sample, but in general about the error. I'm writing it here, because Google directs this error to this question, so it may be useful for the other devs.
Another use case when you can receive such error is when you're adding a selector to method in another class, eg:
private class MockTextFieldTarget {
private(set) var didCallDoneAction = false
#objc func doneActionHandler() {
didCallDoneAction = true
}
}
And then in another class:
final class UITextFieldTests: XCTestCase {
func testDummyCode() {
let mockTarget = MockTextFieldTarget()
UIBarButtonItem(barButtonSystemItem: .cancel, target: mockTarget, action: MockTextFieldTarget.doneActionHandler)
// ... do something ...
}
}
If in the last line you'd simply call #selector(cancelActionHandler) instead of #selector(MockTextFieldTarget.cancelActionHandler), you'd get
use of unresolved identifier
error.

SourceKitService crash related to protocol?

My code is compiling and running properly, but I'm getting continual crashes of SourceKitService. The crashes only occur when I work in or reference files that implement a particular protocol.
If I remove the protocol from the classes, no more crashes.
Further, if I edit the protocol itself to comment out the two methods
in it, no more crashes.
(and yes, I have deleted DerivedData. I have cleaned the project, deleted Xcode, rebooted my computer, reinstalled Xcode, etc. None of those solve the issue)
So this causes continual crashes when editing or referencing implementing classes:
protocol JSONable {
typealias ItemType
func toDictionary() -> NSDictionary
class func fromJSON(json: JSON) -> ItemType?
}
But this doesn't seem to give Xcode any problems at all:
protocol JSONable {
typealias ItemType
// func toDictionary() -> NSDictionary
// class func fromJSON(json: JSON) -> ItemType?
}
(It also crashes if just one of those lines is uncommented)
Any ideas as to what could be causing this? I don't want to have to move away from using the protocol and using asserting "virtual" methods in my base classes, but I can't keep working with the IDE this way.
I have very similar problem. My current solution is to bring the protocol and the class in the same file. This solves the problem, but of course cannot me a permanent solution.

Resources