I'm migrating objective C to swift. I'm getting the error Cannot find 'NSUtils' in scope in the line-
_idInstance = NSUtils.sha256(_idInstance)
I have the NSUtils class in objective C. The function is also mentioned there and it's working well with other .m files:
+ (NSString *)sha256:(NSString *)clear {
....
}
The autofill suggestions also don't show for this. Please help.
In Swift, you should really use CryptoKit instead:
import CryptoKit
let digest = SHA256.hash(data: myData)
let digestString = String(bytes: digest.map { $0 }, encoding: .ascii)!
Related
I have been following this tutorial, which is talking about how to communicated from React Native and objective C. I followed the tutorial, and got a good result. The problem started when I wanted to add a new function called sendData. This would be called in JS and it would pass a string, and in objective C, it would receive the string.
But, the bridging wasn't working.
Here is my code:
RCT_REMAP_METHOD(sendData : (NSString*)str,
sendData_resolver:(RCTPromiseResolveBlock)resolve
sendData_rejecter:(RCTPromiseRejectBlock)reject)
{
BOOL response = [_cppApi sendData];
resolve(response);
}
This code gives the error No visible #interface for 'CCCppCom' declares the selector 'sendData' in Xcode. (CCCppCom is a header file)
another function I have, which is getData seems to work fine.
RCT_REMAP_METHOD(getData,
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
NSString *response = [_cppApi getData];
resolve(response);
}
I'm not entirely sure what is going on here. I checked CCCppCom, and sendData is indeed there.
Can someone help me? Thanks in advance.
I solved the problem by using RCT_EXPORT_METHOD instead of RCT_REMAP_METHOD.
Some background: I'm building an app in react native that uses an Objective C library written about 6 or 7 years ago, maybe older. I'm writing swift code that has been set up to send callbacks to the react native application in JS. I have this function that I'm trying to use:
token = service.getUserToken(server,
port: P2PFunctions.tls_port,
appId: P2PFunctions.appID,
appSecret: P2PFunctions.appSecret,
phone: P2PFunctions.phone,
token: nil, errcode: errCode, errmsg: nil);
callback(["\(token!)"]);
And this is its definition:
- (NSInteger)getUserToken:(NSString*)ip_In port:(NSInteger)port_In appId:
(NSString*)appId_In appSecret:(NSString*)appSecret_In phone:
(NSString*)phoneNum_In token:(NSString**)accessTok_Out errcode:
(NSString**)strErrCode_Out errmsg:(NSString**)errMsg_Out;
These are the types I'm using (EDIT: I changed them from private to public, and they still are not being recognized):
The problem is, I'm getting nil back from the function. I believe I'm getting an HTTP response that is empty, and I notice that inside the debugger when I step to the Objective C function, I see nil for all my parameters inside of the Objective C function. I think... it is that I'm not passing the correct type. Or my Swift parameters are not visible in Objective C's memory space. If it is expecting an (NSString *), should I be passing a String?
How do I pass the correct types from Swift to Objective C? What would I change in my function call? Are my parameter types okay? I cannot edit the original Objective C library. They share a common memory space for all variables in the entire program, right?
Thank you so much!
I just ran this successfully:
// the objc part
#interface Test : NSObject
- (NSInteger)getUserToken:(NSString*)ip_In
port:(NSInteger)port_In
appId:(NSString*)appId_In
appSecret:(NSString*)appSecret_In
phone:(NSString*)phoneNum_In
token:(NSString* _Nonnull * _Nonnull)accessTok_Out
errcode:(NSString* _Nonnull * _Nonnull)strErrCode_Out
errmsg:(NSString* _Nonnull * _Nonnull)errMsg_Out;
#end
#implementation Test
- (NSInteger)getUserToken:(NSString*)ip_In
port:(NSInteger)port_In
appId:(NSString*)appId_In
appSecret:(NSString*)appSecret_In
phone:(NSString*)phoneNum_In
token:(NSString**)accessTok_Out
errcode:(NSString**)strErrCode_Out
errmsg:(NSString**)errMsg_Out {
*accessTok_Out = #"Token";
*strErrCode_Out = #"OK";
*errMsg_Out = #"msg";
return 42;
}
#end
// and the swift part
let t = Test()
var token: NSString = "t"
var errcode: NSString = "c"
var errmsg: NSString = "m"
let result = t.getUserToken("ip", port: 1,
appId: "2", appSecret: "3", phone: "4",
token: &token, errcode: &errcode, errmsg: &errmsg)
print(result)
and it works as expected.
Maybe this gives you a hint as to what's different in your situation.
So, after spending a week or so on this problem, I realize that it was not that the parameters are not actually being passed, but that the debugger is just not displaying the values of those parameters, at least on the main thread. Because I was getting the error code, I thought that something had to be wrong with the way I called the function - but actually, the function call is fine, the variables just didn't appear in the debugger for some reason:
Variables above appear to be nil - but in fact, they do have values.
I have a completion handler in a framework written in Objective C...
This is a typedef for a block type. It takes an array of PHErrors.
typedef void (^PHBridgeSendErrorArrayCompletionHandler)(NSArray *errors);
When I try to use this in Swift, I'm doing....
anObject.aMethod(completionHandler: { (errors: [ AnyObject?]) -> () in
...rest of code
}
But I keep getting this error:
Cannot convert value of type '([AnyObject?]) -> ()' to expected argument type 'PHBridgeSendErrorArrayCompletionHandler!'
Can anyone help, I'm baffled, it looks like it should work to me.
Or better yet, you can still use your typedef as typealias.
DEFINE
typealias PHBridgeSendErrorArrayCompletionHandler = (_ errors: [Error]?) -> Void
IMPLEMENTATION
func myFunctionWithErrorCompletion(completion: PHBridgeSendErrorArrayCompletionHandler) {
// Define empty array to add errors to
var errors:[Error]?
// Do Your Logic that may store errors to array
// Completion and pass errors
completion(errors)
}
USAGE
func anotherOfMyFunctions() {
// Call the function
myFunctionWithErrorCompletion { (errors) in
if let completionErrors = errors {
// React to errors
}
}
}
anObject.aMethod(completionHandler: { (errors: [ AnyObject?]) -> () in
}
should be
anObject.aMethod() { errors in
}
In order to dig any deeper, I have to know what PHBridgeSendErrorArrayCompletionHandler is
So my friend solved this problem by simply changing AnyObject to Any
(errors: [Any]?) in
Which baffles me because all objects in an NSArray are objects! So didn't think to try Any.
Im pretty new to Swift mind
Try this..
anObject.aMethod(completionHandler: { (errors:NSArray?) -> () in
...rest of code
}
I'm trying to bitwise compare NSFontSymbolicTraits and NSFontBoldTrait in Swift.
In Objective-C it'd be done like this:
BOOL isBold = (fontDescriptorSymbolicTraits & UIFontDescriptorTraitBold);
So I'm thinking it should be this in Swift:
let isBold:Bool = font.fontDescriptor.symbolicTraits & NSFontBoldTrait
...However that results in the following error:
Cannot invoke '&' with an argument list of type '(NSFontSymbolicTraits, Int)'
Anyone know what I'm missing? Any help would be greatly appreciated.
Notes:
I've Googled like a madman and spend hours trying to find a solution and read through the documentation for NSFontDescriptor and the other NSFont-related classes.
I don't know Obj-C very well so I don't know if it's because the NSFont*Trait constants are implemented differently in Swift? Not even sure if that's the case.
In Swift, NSFontSymbolicTraits is a type alias for UInt32. So to check for the existence of a particular trait, you need to compare the result of your bitwise & to zero. Unfortunately, the individual constraints have been imported as type Int, so you also need to convert them to the right type:
let isBold = 0 != (font.fontDescriptor.symbolicTraits & NSFontSymbolicTraits(NSFontBoldTrait))
If you wanted to do this in iOS (instead of OS X), UIFont has a different implementation. UIFontDescriptorSymbolicTraits is a RawOptionSetType, so you compare the result of your & with nil:
let isBold = nil != (font.fontDescriptor().symbolicTraits & UIFontDescriptorSymbolicTraits.TraitBold)
Update based on Nates answer, since his iOS version doesn't work for me. Which most likely is due to the changes in swift since 2014.
iOS, Swift 4(.2):
extension UIFontDescriptor {
var isBold: Bool {
if 0 == (symbolicTraits.rawValue & UIFontDescriptor.SymbolicTraits.traitBold.rawValue) {
return false
} else {
return true
}
}
}
In Swift 5.4 on iOS.
let isBold = font.fontDescriptor.symbolicTraits.contains(.traitBold)
I'm trying to use the PRTween library in a Swift iPhone app.
Original example code from GitHub:
PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:100 endValue:200 duration:3];
PRTweenOperation *operation = [[PRTweenOperation new] autorelease];
operation.period = period;
operation.target = self;
operation.timingFunction = &PRTweenTimingFunctionLinear;
My Swift port:
var period = PRTweenPeriod.periodWithStartValue(100, endValue: 200, duration: 3) as PRTweenPeriod
var operation = PRTweenOperation()
operation.period = period
operation.target = self
operation.timingFunction = PRTweenTimingFunctionLinear
Xcode is giving me this error:
'PRTweenOperation' does not have a member named 'timingFunction'
I'm not sure how to fix this. I can clearly see the member definition in PRTween.h. I'm thinking it might be related to the fact that this is where the definition of PRTweenTimingFunction takes me.
typedef CGFloat(*PRTweenTimingFunction)(CGFloat, CGFloat, CGFloat, CGFloat);
Has anyone else seen an error like this? Any suggestions for fixes?
P.S. I'm not really sure what to call that typedef. Is it a function pointer?
EDIT
As a workaround, I used this code that does not ask for a timing function:
let period = PRTweenPeriod.periodWithStartValue(100, endValue: 200, duration: 2) as PRTweenPeriod
PRTween.sharedInstance().addTweenPeriod(period,
updateBlock: { (p: PRTweenPeriod!) in
NSLog("\(Int(p.tweenedValue))"
},
completionBlock: { NSLog("Completed tween") })
Yes, that's a function pointer. This is a current limitation of C interoperability:
Note that C function pointers are not imported in Swift.
You might consider filing a bug if you'd like this to work. (Note that block-based APIs are fine and work with Swift closures.)