iOS Framework - Use of undeclared identifier - ios

I am currently trying to create my own custom iOS framework using Swift 2.3. I have a test iOS app, written in Obj-C, and it embeds + links to the custom framework.
The framework has multiple classes, two of them resembling the below:
public class Constants: NSObject
{
private static let sharedInstance = Constants()
override init() { }
public static let CONST_VALUE1 = "somevalue1"
public static let CONST_VALUE2 = "somevalue2"
}
and
public class RandomUtils: NSObject
{
private static let sharedInstance = RandomUtils()
override init() { }
public static func randomFunction(someValue: String) -> String?
{
return someValue
}
}
The RandomUtils class has no problems being seen and used in the test app. The Constants class however, cannot seem to be found, despite it being referenced to in the SDK-Swift.h header:
SWIFT_CLASS("_TtC6sdk9Constants")
#interface Constants : NSObject
+ (NSString * _Nonnull)CONST_VALUE1;
+ (NSString * _Nonnull)CONST_VALUE2;
#end
SWIFT_CLASS("_TtC6sdk16RandomUtils")
#interface RandomUtils : NSObject
+ (NSString * _Nonnull)randomFunction:(NSString * _Nonnull)someValue;
#end
In my test app, I am importing the framework umbrella header file in my ViewController's header file as such:
#import <UIKit/UIKit.h>
#import <SDK/SDK-Swift.h>
#interface TestVC : UIViewController
#property (weak, nonatomic) IBOutlet UITextField *txtValue1;
#end
Attempts to use the Constants class
NSLog(#"%#", [Constants CONST_VALUE1]);
result in this error message
Use of undeclared identifier 'Constants'
Does anyone have any idea what I could be doing wrong?

After some trial and error, I resolved the issue by placing the .framework directly into the test app folder.

Related

Accessing Swift Protocol in Objective C and then back on Swift

I'm a new comer into Objective-C and swift and I need to make changes to an existing code base.
I have added a protocol defined in Swift
File AController.swift
#objc
protocol MyDelegate: NSObjectProtocol {
func saveTapped()
func discardTapped()
}
#objc
class AController: UIViewController, BcAiDelegate {
...
}
The protocol is used as a member is BController.h
and the code compiles and builds w/o issues
// imports are placed here
// #class declarations are here
#protocol MyDelegate;
...
#property (nonatomic) MyDelegate* myDelegate;
#property (nonatomic) BOOL myFlag;
And then I try to access this field in CController.swift
#objcMembers class CController: UIViewController {
...
func doSomething() {
let bController = BController()
// When I try to access `myDelegate` it isn't recognized as a member of the controller
// I get an error message that says - Value of type 'BController' has no member 'myDelegate'
bController.myDelegate = nil
bController.myFlag = true // This lines works fine
}
...
}
If I look at the swift 5 interface generated from BController.h I can see the following definitions:
...
open var myDelegate: UnsafeMutablePointer<Int32>!
open var myFlag: Int33
...
I tried created new initializers in BController.h, one that receives a Bool and the other that receives MyDelegate - and the behavior is the same, the one with Bool is accessible in CController.swift and the other isn't
Obviously I'm missing some part - but what?

"No visible #interface for 'MySwiftFile' declares the selector '****'" in iOS framework

I've been having trouble with using Swift in an ObjC framework in iOS. My framework has Objective-C code, which I want to call Swift code from.
I think I have created the bridging properly, I'll show below what I've done.
MySwiftFile.swift :
open class MySwiftFile: NSObject {
var varDummy : RandomType? = nil
open func setupDummy(param1 : RandomType1) {
varDummy = RandomType(p: param1)
}
}
MyObjCFile.m :
#class MySwiftFile;
#import "MyFramework/MyFramework-Swift.h"
#interface A : NSObject<...>
#property(atomic) MySwiftFile *mySwiftFile;
.....
#end
#implementation Aclass
......
#end
#interface B ()
....
#property(readonly, nonatomic) A *refA;
#end
#implementation B
....
- (void)methodCalledSomewhere:(RandomType1 *)type {
....
refA.mySwiftFile = [[MySwiftFile alloc] init];
[refA.mySwiftFile setupDummy: type]; <====THIS LINE PRODUCES THE ERROR
}
....
To sum it up, I want to init the property and call a function of a Swift object from ObjC code. Xcode seems to recognize MySwiftFile as a valid type, then how come it does not allow me to call the "setupDummy" method?
The errors are 2:
No visible #interface for 'MySwiftFile' declares the selector 'setupDummy:'
No visible #interface for 'MySwiftFile' declares the selector 'setupDummy'
First problem is that you forget to expose it to the Objective-C. Either add #objcMembers to expose everything ...
#objcMembers
open class MySwiftFile: NSObject {
...
}
... or just add #objc to your setupDummy function ...
#objc
open func setupDummy(param1: String) {
...
}
Second problem is about how the function name is translated to Objective-C ...
#objc func setupDummy(param1 : RandomType1) -> setupDummyWithParam1:
#objc func setupDummy(_ param1: RandomType1) -> setupDummy:
#objc(setupDummy:) func setupDummy(param1: String) -> setupDummy:
... which means that adding just #objc wont work. You have to either change the Swift function signature or use setupDummyWithParam1: in your Objective-C or keep the Swift function signature & use #objc(<name>) to change the Objective-C selector.

Swift ViewModel properties can't access in ObjC

In Swift project contains,
CartViewModel.swift
#objc public class CartViewModel: NSObject {
let apiService: APIService
var alertMessage: String? {
didSet {
self.showAlertClosure?()
}
}
var isShow: Bool = false {
didSet {
self.updateStatus?()
}
}
#objc public var dataCount: Int {
return models.count
}
}
ListViewController.h
NS_ASSUME_NONNULL_BEGIN
#class CartViewModel;
#interface ListViewController : UIViewController
#property (nonatomic, strong) CartViewModel *viewModel;
#end
NS_ASSUME_NONNULL_END
ListViewController.m
NSLog(#"%#", self.viewModel.dataCount);
// Accessing any property gives this error
Property 'dataCount' cannot be found in forward class object 'CartViewModel'
If you want to be able to access properties of a class inside the implementation file of an Objective-C class, you need to import the header of the class. Simply forward declaring the class by doing #class YourClass only makes the type itself visible, but it doesn't expose its properties/methods.
Since Swift files don't have headers, you need to import the Swift header of your module.
So in your ListViewController.m do
#import <YourModule/YourModule-Swift.h>
In your Objective-C implementation you need to import the Xcode-generated header file for Swift. Add this to your imports replacing ProductModuleName with your target's name:
#import "ProductModuleName-Swift.h"
Just in case anyone else comes here with this problem; used #class and imported the Swift header but the problem is not solved yet... Double check you have made your Swift class public and not internal

"unrecognized selector sent to instance" when setting a property on react-native

I'm trying to link my Swift view with my React-Native project. I figured out how to display it, but now when I'm trying to set a property, I'm having this error message:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Switch setMessage:]: unrecognized selector sent to instance 0x7f96b270de70'
In my react-native code, I'm doing:
const SwitchNative = requireNativeComponent('Switch', Switch);
class Switch extends Component {
render() {
return (
<SwitchNative message="message will be" style={this.props.style} />
);
}
}
Then doing this in my SwiftBridge:
// SwiftBridge.h
#import "RCTView.h"
#interface SwitchBridge : RCTView
#property (nonatomic, assign) NSString *message;
#end
// SwiftBridge.m
#import "RCTBridgeModule.h"
#import "RCTViewManager.h"
#import "SwitchBridge.h"
#interface RCT_EXTERN_MODULE(SwitchManager, RCTViewManager)
RCT_EXPORT_VIEW_PROPERTY(message, NSString)
#end
Then finally I have this in my Swift class Switch.swift:
...
public func setMessage(message: String) {
NSLog("It's working well");
}
...
Not sure why it can't find my setMessage function.
React Native is trying to call -[Switch setMessage:] but you've defined -[Switch setMessage] without any parameters. Add a parameter to your Swift method signature:
public func setMessage(_ message: String)
You might also need to annotate your method with #objc depending on your version of Swift.
The correct syntax is now in swift,
#objc(setMessage:)
public func setMessage(message: String) {
NSLog("It's working well");
}
This is change for Swift > 3.2, Mac High Sierra and React Native >= 0.43
For anyone might be searching for passing an array of objects from React-Native (I ran into this issue while doing that):
YourView.h:
#interface YourView : RCTView
#property (nonatomic, assign) NSMutableArray *markers;
#end
YourView.m:
...
RCT_CUSTOM_VIEW_PROPERTY(markers, NSMutableArray, YourView)
{
[view setMarkers:json];
}
YourView.swift:
#objc(setMarkers:)
public func setMarkers(json: NSMutableArray) {
}

use swift class in Objc project

In one of my projects I want to use a Swift class from an Objective C class. I've created XXX-swift.h file and a bridging header file. Most swift files are working perfectly, but I found a problem of an APiResult class of mine.
#objc class ApiResult:NSObject {
var success:Bool?
var message:String?
}
and in XXX-swift.h file
SWIFT_CLASS("_TtC16RemoteController9ApiResult")
#interface ApiResult : NSObject
#property (nonatomic, copy) NSString * _Nullable message;
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
#end
there the success property is missing. A rebuild & clean build didn't work.
Why is this happening
Objective-C doesn't support optionals. The bridging from Swift to Objective-C allows optionals for class types because those just translate to nil on the ObjC side. However, Bool is a primitive type, and there's no such thing as a nil boolean value in Objective-C.

Resources