Obj-c exporting .h files for a Static Library - don't want to expose class definition - ios

I am struggling to create an iOS static library correctly/cleanly.
So far I have used Extension a to create a separation between my internal (private) .h declarations and the public .h declaration (that gets exported).
I have "successfully" created the library and seen it working. However I am still exposing the class declaration in the public WTDevice.h
#interface WTDevice : NSObject <WTMinorStateDelegate,CBPeripheralDelegate>
As WTDevice inherits from WTMinorStateDelegate I have to export protocol WTMinorStateDelegate too, which I don't wish todo as this is only used within the library.
BTW the WTDevice extension is in WTDevice_internal.h which doesn't get exported.
I am sure there is a way of putting the line:
#interface WTDevice : NSObject <WTMinorStateDelegate,CBPeripheralDelegate>
into WTDevice.m (making it private), however I have failed so far. The question is what replaces it when I remove it from the WTDevice.h file?
Thanks

In WTDevice.m add this before the #implementation block to create a private category.
#interface WTDevice () <WTMinorStateDelegate>
#end
In WTDevice.h remove WTMinorStateDelegate from the #interface line.

Related

Receiver '**' for class message is a forward declaration Error. Swift Static Library use in Objective-C

I am trying to make a Swift Static library and apply it to Swift and Objective Project.
import Foundation
#objc open class Library001_Test: NSObject {
public override init(){}
#objc public func testPrint() {
print("My Name is Andi")
}
#objc public func getUUID(userName: String) -> String {
let uuid = UUID().uuidString
return "\(userName)'s UUID : \(uuid)"
}
}
I wrote the code like this using Swift.
And in the Edit Scheme menu, I changed the Build Configuration to Release and proceeded with Run. As a result, the 'libLibrary001.a' file and the 'Library001.swiftmodule' folder were created.
These two artifacts work well when pasted into a Swift project and imported.
But the problem is an Objective-C project.
I put both artifacts into my project and checked:
[General - Frameworks, Libraries. and Embedded Content] whether the library is recognized
Whether the library is recognized in [Build Phases - Link Binary With Libraries]
Check [Build Settings - Library Search Paths] address
Defines Module - Yes
And I put '#class Library001_Test;' in ViewController.h
#import <UIKit/UIKit.h>
#class Library001_Test;
#interface ViewController : UIViewController
#end
And in ViewController.m, '#import "ProductName-Swift.h" and the created Class were loaded.
#import "ViewController.h"
#import "SwiftInObjectiveC-Swift.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
Library001_Test *test = [[Library001_Test alloc] init];
}
#end
error : Receiver 'Library001_Test' for class message is a forward declaration
error : Receiver type 'Library001_Test' for instance message is a forward declaration
An error occurred while doing this. I've tried all the methods I've found on the internet and I'm wondering where the problem is.
Is the code the problem? Did I not set it up well??
The Swift file created in the project is import well in Objective-C... Why the hell is the .a file not working like this?
My problem was with '(ProductName)-Swift.h'
If you look at how Swift Code is used in Objective-C, many articles say to import (ProductName)-Swift.h. So I only added the project header that I want to apply, but I also need to add the product header made from the library.
My problem was simple, but it took me a long time to figure it out. The error was not found 'Class' and 'func' in Swift static library. My workaround was resolved using the (LibraryProductName)-Swift.h of the library I created, rather than the (ProductName)-Swift.h of the project you are working on.
If you refer to the address below, you can prevent the error that occurred in advance.
https://medium.com/#mail2ashislaha/swift-objective-c-interoperability-static-libraries-modulemap-etc-39caa77ce1fc

My custom native module is not present inside NativeModules object

So, i wanted to create a native module which will detect, if the app is running on emulator/simulator or an actual device.
Everything works fine on android, but i'm facing issue on iOS.
I have create a AbcModule.h and a AbcModule.m file
#import <React/RCTBridgeModule.h>
#interface AbcModule : NSObject <RCTBridgeModule>
#end
This is AbcModule.h
#import "AbcModule.h"
#implementation AbcModule
RCT_EXPORT_MODULE(GetDetails);
- (BOOL) xyzFunctn {
#if TARGET_IPHONE_SIMULATOR
return YES;
#else
return NO;
#endif
}
RCT_EXPORT_METHOD(xyzFunctn: (RCTPromiseResolveBlock)resolve rejecter: (RCTPromiseRejectBlock)reject) {
resolve self.xyzFunctn;
}
#end
This is AbcModule.m
Here i have followed the react native documentation for implementing the Native Modules.
But i'm consistently facing this error which says
"TypeError null is not an object, evaluating GetDetails.xyzFunctn"
I have went through several solutions and articles but nothing seems to be working here.
Need help guys!
from the docs
If you do not specify a name, the JavaScript module name will match the Objective-C class name, with any "RCT" or "RK" prefixes removed.
so just do not specify any name,
#implementation AbcModule
// To export a module named AbcModule
RCT_EXPORT_MODULE();
#end
in your case it should then be accessible from within JS with
AbcModule
But the documentation is not clear if the Objective-C Class declaration needs to be written with prefixed "RCT" or "RK".. but because both prefixes seem to be valid, you should be able to just use AbcModule without prefix.
In other words, if you want to use GetDetails from within JS you need to name your interface and implementation accordingly
#implementation RCTGetDetails
RCT_EXPORT_MODULE(GetDetails);
// or
// RCT_EXPORT_MODULE();
#end
Okay, if there is someone who is facing this issue and feels like their code should work but it isn't and any solution online not working for you as well.
Try this:
When you create your .h and .m file for header and objective-c or swift file, make sure you do it in Xcode and not from VSCode.
VSCode eventually doesn't adds you .h file in the required resources folder, i have wasted my 2 weeks trying to find out solution for it, but lastly, that was it, yes this is it.
in your .m file, let's say GetDetails is a class of NSObject .swift
you need:
#interface RCT_EXTERN_MODULE(WidgetManager, NSObject)
// method to export
RCT_EXTERN_METHOD(isAuthenticated: (BOOL *)isAuthenticated)
#end
in your GetDetails.swift:
#objc(GetDetails)
class GetDetails: NSObject {
#objc(isAuthenticated:)
func isAuthenticated(_ isAuthenticated: Bool) {
}
}

Allow change in property only from one specific class

Suppose I have a class Participant which looks like this
Participant.h
#interface Participant : NSObject
#property(nonatomic, readonly) NSString *name;
#property(nonatomic, readonly) NSString *id;
#end
Here properties are readonly because I don't want anyone using this interface to change it
Besides ParticipantManager.h
What changes should I do in Participant class and how would I create ParticipantManager such that only ParticipantManager can change properties of Participant
More context
I get an event from react-native when value changes. to keep things in sync, I want my interface ParticipantManager to only change the values.
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
#interface ParticipantManager : RCTEventEmitter <RCTBridgeModule>
#end
^^ Above class should only be able to change properties of Participant class
For a user to change a value, he would call changeName method, which will send an event back to react-native where react-native would change value and send back to native code
what I have tried.
So, I thought about using class extensions concept but I am getting an error.
Here is what I did
I create Participant+Private.h which implements setName method
#import " Participant.h"
interface Participant()
- (void)setName:(NSString)name
- (void)setId:(NSString)name
#end
PS: I implemented setName and setId method in Participant.h
- (void)setName:(NSString)name {
_name = name;
}
but then when I am using it in my ParticipantManager.h, it is throwing error
No visible #interface for Participantdeclares the selector
setName
I am using it like this
#import "Participant+Private.h"
NSString* value = #"varun";
[[Participant sharedInstance] setName:value];
Can someone help me in fixing error?
Slightly detailed question here:
No visible #interface for Participant declares the selector setName
Objective-C doesn't provide that sort of reasoned privacy, e.g. "I am private to everyone except one other specific class which I hereby name". (Actually, I don't know any language that behaves that way, but that's not to say that there are no such languages of course.)
If this is a framework, you can use #package privacy to confine the privacy of something to other classes in the same framework.
Otherwise, Objective-C generally solves the visibility problem by importing headers, so if you put public accessors for Participant into a header and the only class that imports that header is ParticipantManager, then only ParticipantManager sees them.

Make a objective C method that uses a swift protocol as parameter public accesable

I have an objective-c method that uses a swift protocol as a parameter type. The signature looks like + (void) my_ObjC_method: (id<my_Swift_protocol>) parameter_name;
I generally know how to make swift protocols accessible to objective C.
I implemented it this way:
#objC protocol my_Swift_protocol : class {
//...methods go here
}
My problem is that I want to make my_ObjC_method public accessible. That would normally be done by simply adding it to the header file in the #interface part. Sadly, this requires to import the bridging header to the .h file, so that the .h file knows my swift protocol and recognizes it as a valid type. But you can't import the automatically generated bridging header into other header files.
What would be a good approach to solve or work around this problem?
Maybe you can use #protocol directive as a forward declaration.
MyClass.h:
#import <Foundation/Foundation.h>
#protocol my_Swift_protocol;
#interface MyClass : NSObject
+ (void) my_ObjC_method: (id<my_Swift_protocol>) parameter_name;
#end

#import ProjectName-Swift.h into header file Can't use swift as .h property?

So I'm trying to use an #objc swift class as a property on my objective-c header file.
example
#objc class SwiftClass: NSObject {
}
#interface ObjcObject : NSObject
#pragma mark - Public Properties -
#property (nonatomic, weak) SwiftClass* swiftClass;
However if I #import ProjectName-Swift.h it gives me the error that "'ProjectName-Swift.h'file not found'
I found an answer here that implies you can't actually import Swift into a header file https://stackoverflow.com/a/29951314/3877767
How then am I supposed to use swift code together with objc code? I would not call swift and objc interoperable if you can't use #objc marked swift classes as properties on and objc header file
So inside of my App-Bridging-Header.h
#import "ObjcClass.h"
and inside of my ObjcClass.h
#import "ProjectName-Swift.h"
This gives the error ProjectName-Swift.h can't find file
Either removing the #import ProjectName-Swift.h, or the #import ObjcClass.hfixes the problem, but then I can't use the Swift/OBJC code respectively
You don't import the header file. You give it to the compiler as a so-called "bridging header" that tells the compiler what to share between the two language environments.
You need to put your header file under the Objective-C Bridging Header as shown below:

Resources