I have a swift app where I use the native C++ lib and there is a method that takes as an argument void * on MTLTexture
void RenderAPI_Metal::EndModifyTexture(void* textureHandle)
{
id<MTLTexture> tex = (__bridge id<MTLTexture>)textureHandle;
...
}
and Swift call is
func foo(texture: MTLTexture) {
...
EndModifyTexture(&texture)
...
}
So, on the Swift side, I call the method and pass a pointer, and then on the C++ side when I try to cast it back I got an error
om.apple.scenekit.scnview-renderer (20): EXC_BAD_ACCESS (code=1, address=0x0)
So, according to the error looks like the pointer is nil, however, when I check it in the debug I see that it has an address void* textureHandle is 0x0000000280a08178
What is the problem here? Why did I pass MTLTexture and then I got a problem casting it back?
P.S.
I can't change the implementation, C++ method should receive void*
Thanks to #MartinR I found the solution here
https://stackoverflow.com/a/33310021/5709159
exactly this method helps me to solve the problem
func bridgeRetained<T : AnyObject>(obj : T) -> UnsafeRawPointer {
return UnsafeRawPointer(Unmanaged.passRetained(obj).toOpaque())
}
Related
I've got a method written in Objective-C which returns a BOOL, for example:
(BOOL)methodName:(NSDictionary<NSString *, NSString *> *)params callback:(void(^)(NSString *_Nullable, ErrorInformation *_Nullable))callback error:(NSError *_Nullable *_Nullable)errorPtr;
Usage in Swift
I get the error, Cannot convert value of type '()' to expected condition type 'Bool'. I thinks that ret is of type (), instead of BOOL. Looking at the implementation, this value is mutated inside dispatch_sync.
let ret = try! methodName()
// I've tried a bunch of different syntaxes below:
if (ret) { <--- Xcode warning: Cannot convert value of type '()' to expected condition type 'Bool'
}
It is not nice to see this method has 3 ways of indicating failure, but I didn't design it 😅 and frankly my objective-C is not good:
errorPtr, which is automatically turned into do/try/catch in Swift
ErrorInformation passed in the callback
BOOL return value, which I am struggling with.
The returned BOOL is part of the NSError processing that is converted in Swift into a throws function (if the method returns a value, Swift will convert it from nullable to nonnull).
YES is returned if the method succeeds (there is no error), NO is returned when the method fails.
In Swift:
do {
try methodName()
// method succeeded
} catch {
// method failed
}
The ErrorInformation in the callback is probably related to asynchronous errors, probably similar to a Result<String, Error> in Swift.
References:
Handling Error Objects Returned From Methods (Obj-C)
Improved NSError Bridging (Swift Evolution 0112)
After working with Objective-C for a long time I have just started to work with Swift as well.
I know that Swift uses the Error protocol instead of NSError and in future I will use custom Error implementations as well. However, currently I need to work with NSError in Swift and I found the following code to easily access NSError properties on Error:
extension Error {
var code: Int { return (self as NSError).code }
var userInfo: [AnyHashable? : Any?] { return (self as NSError).userInfo }
}
While I found an example for the code part in an answer here, I added the userInfo part myself. It is now problem to access someError.code using this extension. However, when using someError.userInfo the app chrashes after calling the getting over and over again.
Xcode shows a warning which explains the source of the problem:
All paths through this function will call itself
Why is this?
As far as I know Error is just a protocol which can be implemented by any class. Error it self does not have code or userInfo properties, so (self as NSError).userInfo should not callError.userInfo`, should it?
So I do not understand why this is a problem. Additionally I do not understand why this is a problem for userInfo but not for code...
Any idea what's the reason for this?
Alright guys, I'm struggling with this: I already managed to make custom functions without arguments work like this:
NSExpression(format: "function(1+1, 'myCustomFunction'").expressionValueWithObject(nil, context: nil) as! Double
But I have no idea of how to implement a custom function with arguments, I already tried passing the following String to NSExpression without success:
"function(1+1, 'myCustomFunctionWithArgument(42)')" // 42 as the argument
where the custom function looks like:
public extension NSNumber {
func myCustomFunctionWithArgument(x: Double) -> NSNumber
//...
}
However I get the following error:
-[__NSCFNumber myCustomFunctionWithArgument(42)]: unrecognized selector sent to instance 0xb000000000000045
2016-03-14 18:23:00.755 MyApp[3517:263390] *** Terminating app due to uncaught exception
I already searched everywhere, and I only find Objective-C answers, like on this tutorial:
https://spin.atomicobject.com/2015/03/24/evaluate-string-expressions-ios-objective-c-swift/#comment-549856
In the end he explains how to do it on Objective-C, but not in Swift. Is there any way to do it? Btw this is for my Calculator app.
I got the code below to work in an Xcode 7.2.1 playground. The error you received had to do with the selector, and the main thing to keep in mind for selectors is that you need a colon (:) after the name of the function in this case to signify that the function has a single parameter.
import Foundation
public extension NSNumber {
func myCustomFunctionWithArgument(x: NSNumber) -> NSNumber {
return self.doubleValue + x.doubleValue
}
}
let stringExpression = "function(1+1, 'myCustomFunctionWithArgument:', 42)"
let expression = NSExpression(format: stringExpression)
let result = expression.expressionValueWithObject(nil, context: nil) as! NSNumber
print(result.doubleValue)
I am moving my code from Obj. C to Swift C and trying to implementing the Twitter sdk..
But, I am getting an error...
Can any body tell me what I have done wrong.
Please help me with this.
I spent 2 days tried everything but didn't work for me.
Your block does not have a return statement, therefore the compiler
uses the result of the last statement
UIApplication.sharedApplication().openURL(url)
as return value, which is a Bool and not Void as declared in the block signature.
To solve that problem, just add a return statement:
{ (url: NSURL, oauthToken: String) -> Void in
UIApplication.sharedApplication().openURL(url)
return
}
The problem is that openURL returns a boolean, and an attempt to convert it to Void is made, since the closure is declared as returning a Void. Simply remove that as follows:
{ (url: NSURL, token: String) in
UIApplication.sharedApplication().openURL(url)
}
If you don't want to change the closure signature, just assign the return value to a variable:
{ (url: NSURL, token: String) -> Void in
let ret = UIApplication.sharedApplication().openURL(url)
}
What's not stated in the other answers is that Swift will implicitly add a return to a single statement closure.
This is how statements like conditionSet.sort {$0.set < $1.set} can work.
This can also result in an unexpected error. To avoid the error, make the closure have 2 statements. The simplest way is to add a return after your original statement as stated in the accepted answer.
I try to rewrite some objective c code into swift. Now I get a very strange error. I tried the code in a playgroud, absolutely untouched from other code.
Here is the part, I want to translate:
NSDictionary *info = [self infoForBinding:#"theBinding"];
[[info objectForKey:NSObservedObjectKey]
setValue:MyValue
forKeyPath:[info objectForKey:NSObservedKeyPathKey]];
This is the code, I tried:
class x: NSButtonCell {
func a() {
var info = infoForBinding("theBinding")
info[NSObservedObjectKey]?.setValue(nil, forKeyPath: info[NSObservedKeyPathKey])
}
}
Now I get the error 'NSString' is not convertible to 'DictionaryIndex<NSObject, AnyObject>'. Any ideas?
UPDATE:
This is working... I don't know why.
info[NSObservedObjectKey]?.setValue(MyValue forKeyPath: (info[NSObservedKeyPathKey] as NSString))
The reason that
info[NSObservedObjectKey]?.setValue(MyValue forKeyPath: (info[NSObservedKeyPathKey] as NSString))
works is that as of beta 3, the NSDictionary#getValue method returns a DictionaryIndex object instead of casting it to an NSObject/AnyObject. By explicitly casting it (which is something to get into a good practice of, as the Swift designers seem to be opposed to too much implict casting), you can safely pass it into setValue without any ruckus.