Calling Wrapper Function From Javascript is Crashing App - React-Native - ios

Hello I am trying to call a function in javascript that I am exporting via Objective C. When I call my function in javascript my app is crashing.
RCT_EXPORT_METHOD(getModelAsync:()
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
NSError *error;
NSString *contents = [[UIDevice currentDevice] model];
if (contents) {
resolve(contents);
} else {
reject(#"Test", #"Something is broken",error);
}
}
Its failing on this on the if statement with this Error: Thread 1: EXC_BAD_ACCESS (code=1, address=0x0)
if (!RCTIsIdentifierHead(**input)) {
return NO;
All help is welcome, thanks!

I came across this issue today and managed to solved it. It looks like the function argument types aren't matching up. This error seems to be triggered, when the function types aren't compatible. Something like the following code snippet, would trigger this error, because a dictionary is not compatible with type string and thus the function argument cannot be correctly cast.
Module.m
RCT_EXTERN_METHOD(myFunction: (NSDictionary)options)
Module.swift
#objc
func myFunction(_ options: String) -> Void {
...
}
To fix it, make sure you are doing something like this:
FixedModule.m
RCT_EXTERN_METHOD(myFunction: (NSDictionary)options)
FixedModule.swift
#objc
func myFunction(_ options: NSDictionary) -> Void {
...
}
I hope this helps!

Related

How can I throw an NSError from a Swift class and catch it in an Objective-C class?

I need to implement a try-catch structure in Objective-C to handle Swift thrown NSErrors.
I've written an NetService manager with Swift code and I am implementing it on an already existent Objective-C UI.
However, whenever I throw an error from my Swift class, the try-catch structure fails to catch the error and proceeds to the finally block.
Swift error definition:
enum NEONetServiceErrors: Int
{
case requestMadeWithoutIp
}
struct NEONetServiceErrorStrings
{
let requestMadeWithoutIp = ["NEONetService Error: Request made without IP": NEONetServiceErrors.requestMadeWithoutIp]
}
Swift error throwing:
#objc func requestHelloPage() throws
{
if serviceiPAddress != nil
{
makeHelloRequest()
}
else
{
throw NSError(domain: errorStrings.domain, code: NEONetServiceErrors.requestMadeWithoutIp.rawValue, userInfo:errorStrings.requestMadeWithoutIp)
}
}
Objective-C properties:
#property NEONetServiceManager* netServiceManager;
#property NSError* _Nullable __autoreleasing * _Nullable netServiceError;
Objective-C error handling:
- (IBAction)pressUpdateButton:(id)sender
{
#try
{
[self.netServiceManager requestHelloPageAndReturnError: self.netServiceError];
}
#catch (NSException *exception)
{
NSLog(#"Throwing");
}
#finally
{
NSLog(#"Finally");
}
}
Output:
2019-10-18 14:47:03.289268-0300 NEOFirmUpdate[16533:2389800] Start
2019-10-18 14:47:03.292696-0300 NEOFirmUpdate[16533:2389800] Finally
Could you help me figure out what I am doing wrong with my error-handling?
The problem is that a Swift Error / Objective-C NSError is not an NSException. You are configured to catch NSExceptions but that is irrelevant.
The way to "catch" an NSError in Objective-C when Swift throws an Error is by indirection with the NSError** parameter, just as it always has been.
NSError* err = nil;
BOOL ok = [self.netServiceManager requestHelloPageAndReturnError:&err];
if (ok) {
// proceed normally
} else {
// you got an error, it is sitting in `err`
}
(Notice how Swift supplies a BOOL result exactly so you can implement the correct pattern.)
That's because you're using objective-c exceptions there, and not actually checking for an error. To check for errors in objective-c, you pass a reference to your pointer and your function will fill that error out if there was an issue.
NSError *serviceError = nil;
[self.netServiceManager requestHelloPageAndReturnError:&serviceError];
if (serviceError) {
// there was a problem
}
If this is an asynchronous call, you'll need to do this in a closure instead:
NSError *serviceError = nil;
[self.netServiceManager requestHelloPage:^(NSError *error) {
if (error) {
// there was a problem
}
}];
In your Objective-C code you are Catching and NSException, not an NSError
Swift automatically bridges between the Error type and the NSError
class. Objective-C methods that produce errors are imported as Swift
methods that throw, and Swift methods that throw are imported as
Objective-C methods that produce errors, according to Objective-C
error conventions.
for more information you can click here

Parse iOS - How to capture the findObjects() error being thrown?

I am coding in Swift and attempting to use the findObjects() function for the Parse iOS SDK. However, I can't seem to figure out what type of error is being thrown by Parse if this function call fails. I'm a novice in Swift so that may be my issue. I attempt to call the function in a do->catch block and use the try keyword on the function call however I'm not sure what to catch. I can catch the error using the _ but I would like to grab the description from the error. Thanks!
P.S. I don't want to use the findObjectsInBackground() method.
do {
let object = try query.getFirstObject()
// do something with the object
} catch _ {
// this is where I would like to print out the error description
}
In Obj-C, which I assume will be similar, I print out the error.userInfo[#"error"] parameter of the NSError that is returned.
All you need is print(error). An example here:
func getReferenceNumberAsStringSync() -> String? {
let query = PFQuery(className: "PropertyCount")
do {
let object = try query.getFirstObject()
if let referenceNumber = object["count"] as? Int {
return String(referenceNumber)
}
} catch {
print(error)
}
return nil
}

canEvaluatePolicy Extra argument 'error' in call Swift Xcode 7

I work with Xcode 7 with swift and I would use the Touch Id. Only I have a error when I use canEvaluatePolicy. I understand my error, I call an argument too. Only if I do not call, it makes me a error because I did not manage my error ...
Here are my error and my code:
PS: sorry for my bad English.
Error : Extra argument 'error' in call
or
Error : Call can throw, but it is not marked with 'try' and the error is not handled
My code :
import Foundation
import UIKit
import LocalAuthentication
class touchid : UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var lblTouchId: UILabel!
override func viewDidLoad() {
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
#IBAction func authenticateWithTouchID(sender: AnyObject) {
let authenticationObject = LAContext()
self.pleaseWait()
if authenticationObject.canEvaluatePolicy(.DeviceOwnerAuthenticationWithBiometrics) {
authenticationObject.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason: "Access", reply: {(Bool, authenticationError) in
if authenticationError != nil {
// Authentification annulé ou Touch id non disponible
self.lblTouchId.text = "annulé ou touch id non disponible"
self.clearAllNotice()
self.errorNotice("Erreur !")
}
else {
if Bool == true {
self.lblTouchId.text = "authentification réussi"
self.clearAllNotice()
self.successNotice("Succès !")
}
else {
self.lblTouchId.text = "echec de l'authentification"
self.clearAllNotice()
self.errorNotice("Erreur !")
}
}
}
)
}
}
}
As mentioned in Using Swift with Cocoa and Objective-C, all Objective-C methods that use NSError to return an error object will now throw when called from Swift 2.0, so you need to use:
do {
try method()
} catch let error as NSError {
reportError(error)
}
Removing the reference to NSError in the method() call.
Looking at Apple's documentation, something seems off. The method signature is:
func canEvaluatePolicy(_ policy: LAPolicy, error error: NSErrorPointer) -> Bool
The odd part is that currently, the method doesn't throw anything, so putting it in a do-try block isn't necessary. I don't know if (but my guess is that yes) this framework is still getting tweaked with Swift 2.0, but I thought I remembered it implementing throw at one point in the Xcode/Swift beta iterations. At one point the compiler was acting a little wonky and said that:
1 - the method signature only had 1 parameter, but implements throws (which it doesn't)
2 - But as mentioned above, when you do that, the compiler then gives you different errors.
One thing to point out is that the current method signature, as of this writing, has a second parameter which is an NSErrorPointer, not an NSError? object. Treat it like the current Apple docs suggest, so add something like:
var error: NSErrorPointer?
let canEvaluatePolicty = LAContext().canEvaluatePolicy(.DeviceOwnerAuthenticationWithBiometrics, error: error!)
And your code should compile. It might be a good idea to keep an eye on this framework as more iterations of the beta's come out.
Good Luck!
Although the answer from g_blott does indeed compile, it's not good practice to force unwrap when you're not sure what could happen.
This code also compiles, but doesn't force unwrap anything and handles the existence of an error:
var error: NSError?
let errorPointer: NSErrorPointer = NSErrorPointer(&error)
let canEvaluate = context.canEvaluatePolicy(.deviceOwnerAuthentication, error: errorPointer)
if let error = error {
print("Oh noes, an error! ", error)
} else if canEvaluate {
print("Can evaluate")
} else {
print("Can't evaluate")
}

Swift - Closure in Dictionary Crash

So I had objc code which uses Singleton instance to make pings(using SimplePing) and holds ping request completion blocks. In ObjC it looks like this:
#interface SimplePingClient()
{
NSMutableArray* _currentPings;
NSMutableDictionary* _currentCallbacks;
}
#end
#implementation SimplePingClient
-(id)init
{
if( self = [super init] )
{
_currentPings = [NSMutableArray new];
_currentCallbacks = [NSMutableDictionary new];
}
return self;
}
method to start ping:
-(void)pingHostname:(NSString*)hostName andResultCallBlock:(void(^)(NSString* latency))result
{
TSimplePing* pingClient = [TSimplePing simplePingWithHostName:hostName];
[_currentPings addObject:pingClient];
[_currentCallbacks setObject:result forKey:[NSValue valueWithNonretainedObject:pingClient]];
pingClient.delegate = self;
//some other irrelevant code
...
}
And when SimplePing delegate method is called:
- (void)simplePing:(TSimplePing *)pinger didReceivePingResponsePacket:(NSData *)packet
{
void(^callback)(NSString* latency) = [_currentCallbacks objectForKey:[NSValue valueWithNonretainedObject:pinger]];
if( callback )
{
//some irrelevant code
...
callback(#"123");//hard coded for test, irrelevant code get this value correctly ;)
[_currentCallbacks removeObjectForKey:[NSValue valueWithNonretainedObject:pinger]];
}
[_currentPings removeObject:pinger];
}
So this code work flawlessly on objc. However when I try to port this in Swift I keep get error EXC_BAD_ACCESS. To simplify example I just erased everything and it turns out that storing Closure in Dictionary and immediately call it is not working for me:
typealias callbackClosure = (String) -> ()
class SimplePingClient: NSObject
{
// MARK: variables
var _currentPings = [TSimplePing]()
var _currentCallbacks: Dictionary<String, callbackClosure> = [String: callbackClosure]()
private func ping(hostname: String, resultCallback:callbackClosure)
{
var pingClient = TSimplePing(hostName: hostname)
pingClient.delegate = self
_currentPings.append(pingClient)
_currentCallbacks[pingClient.hostName] = resultCallback
if let callback = _currentCallbacks[pingClient.hostName]
{
callback("123213")//here program CRASHES
}
}
}
As you can see in code I even try using hostname(which is String) instead of NSValue assuming some memory problems, but it's not the case - still crashing. This error however is surely something with memory management, however I cannot understand what I'm doing wrong. If anyone could point me what I'm missing I'll really apreciate it.
As #Owen Hartnett suggested I'm moving solution from answer itself here:
Okay, after another hour of debugging it turns out reason is pretty silly. As I said I'm porting my code, so previously I was using this class as bridged objective-c code, therefore this function:
-(void)pingHostname:(NSString*)hostName andResultCallBlock:(void(^)(NSString* latency))result
was bridged following way:
SimplePingClient.pingHostname(latencyUrl, refreshTime: refreshRate) { (latency: String!) -> () in
if nil != latency
{
//dummy code
}
}
therefore after SimplePingClient became swift class, my new closure signature is(note that now latency is not force unwrapped and is not optional, and also no need to check against nil)
SimplePingClient.pingHostname(latencyUrl, refreshTime: refreshRate) { (latency: String) -> () in
//dummy code
}
So by simply changing method call everything started working. Strange thing that compiler doesn't notice this problem though.

Objective-C completion block in Swift

I would like to call a completion block in Swift as I have always done in Objective-C. I took a look at closures, but for some reason, I cannot get it to work...
Obj-C:
- (void)someMethodWithParam1:(NSString *)param completion:(void(^)(NSArray* arr, NSURLResponse *resp))callback
{
callback(arr, resp);
}
Swift:
func someMethodWithParam1(param: NSString, completion:((NSArray?, NSURLResponse?)->())) ->(){
^
|
/* Error: Insert ',' here */
completion(arr, resp)
}
EDIT
Okay, it was not a syntactical error, but an error from my side. The method header I used here is different from the one in my code. So this code that I originally posted should work fine.
Typealias's are your friend here, just to make the code more readable
typealias onComplete = (NSArray?, NSURLResponse?) -> ()
func someMethodWithParam1(param: NSString, completion:onComplete) -> ()
{
completion(arr, resp)
}

Resources