Cannot invoke initializer for type 'UnsafeMutablePointer' - reachability

I'm trying to update Reachability.swift to swift 3.0 and I'm having trouble passing the Reachability instance to the call back function.
Here is my snippet:
* please note self = Reachability class
var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
context.info = UnsafeMutablePointer(Unmanaged.passUnretained(self).toOpaque())
Where the compiler throws an error saying:
Cannot invoke initializer for type 'UnsafeMutablePointer<_>' with an
argument list of type '(UnsafeMutableRawPointer)'
Pointer conversion restricted: use '.assumingMemoryBound(to:)' or
'.bindMemory(to:capacity:)' to view memory as a type.
Overloads for 'UnsafeMutablePointer<_>' exist with these partially
matching parameter lists: (RawPointer), (OpaquePointer),
(OpaquePointer?), (UnsafeMutablePointer),
(UnsafeMutablePointer?)
What I understand I need to convert self which is of type open class Reachability: NSObject to an UnsafeMutablPointer but Im not sure how to proceed.

Check the type of info property from the latest reference:
Declaration
var info: UnsafeMutableRawPointer?
And the type of toOpaque() has become UnsafeMutableRawPointer.
(I couldn't have found an up-to-date Apple document, but you can check it easily in the Quick Help pane of Xcode.)
You have no need to convert:
context.info = Unmanaged.passUnretained(self).toOpaque()

Related

Typedef Return-Type in Objective-C does not work in Swift

I want to use a Objective-C class in my Swift project and have imported the files and Xcode created the bridge header file and everything is cool... except:
The Objective-C class defines a callback type for a function
typedef void (^SSScanManagerCallback)(BOOL success, NSError *error, NSArray *scannedURLs);
And uses the type in the function declaration
- (void)scanSync:(SSScanManagerCallback)callback; // Synchronous scan.
The class in question is the following: https://github.com/counsyl/scanstream/blob/master/ScanStream/SSScanManager.h#L16
If I then want to use the class in Swift:
let scanManager = SSScanManager();
scanManager.scanSync({(_ success: Bool, _ error: Error, _ scannedURLs: [Any]) -> Void in
if !success {
// ...
}
});
I get the following error:
Cannot convert value of type '(Bool, Error, [Any]) -> Void' to expected argument type 'SSScanManagerCallback!'
Update: Even if I try to set the argument type like so:
scanManager.scanSync({(_ justATry: SSScanManagerCallback!) -> Void in
});
I get the error:
Cannot convert value of type '(SSScanManagerCallback!) -> Void' to expected argument type 'SSScanManagerCallback!'
But how would I set the type to just 'SSScanManagerCallback!' as requested in the error message?
Interestingly, it appears that Swift (tested with 3.0.2) now imports Objective-C block argument types without any nullability annotations as strong optionals (previously they were imported as implicitly unwrapped optionals). I can't seem to find the documentation for this change though.
So in your case, the correct signature is:
scanManager.scanSync {(success: Bool, error: Error?, scannedURLs: [Any]?) -> Void in
// ...
}
But never write it like this, always let Swift infer the argument types where it can, it solves these kinds of type-mismatch problems for you.
scanManager.scanSync { success, error, scannedURLs in
// ...
}
Now you can ⌥ click on the closure arguments and Xcode will tell you the type that Swift infers them to be.

Error accessing function of class while converting Obj C project to Swift

I added my swift class to the target while removing my header file of the same objective C class from the target but this error shows when I try and build my project. I can't attach an image right now but the error states: "Use of instance member 'url' on type 'ServerURLFactory'; did you mean to use a value of type 'ServerURLFactory' instead?"
let accessURL: NSURL = NSURL(string: "\(ServerURLFactory.url())/CygnetInstanceXMLServlet?cygnetId=\(idNumber)")!
print(accessURL)
Has anyone ran into a similar problem and how to fix this confusing bug? Its as if the program is still trying to call the Obj C function instead of explicitly calling the one in the Swift file.
You're calling .url() on ServerURLFactory itself as a type:
ServerURLFactory.url()
I guess you should instantiate the class first. Probably something like this, but it depends on how the class is implemented:
let factory = ServerURLFactory()
Then:
factory.url()

HashMap errors - containsKey, get

Can anyone shed some light?
Problem code:
protected var table = HashMap<Class<*>, Double>()
if (table.containsKey(object)) {
value = table.get(object)
}
containsKey(K):Boolean is deprecated. Map and Key have incompatible
types. upcast to Any? if you're sure
so I changed it to this:
if (table.containsKey(object as Any?)
which fixes the error, but is this what I should have done to fix it? or is there a better way?
also .get(object) has an error:
Type inference failed. required: kotlin.Double found kotlin.Double?
same error message for this too:
val c = someObject.javaClass // pre j2k code: final Class<? extends SomeClass> c = someObject.getClass();
weight = weightingTable[c] <-- error here
I don't know what to do here
The containsKey call is reported as an error because the type of the argument you pass to it does not match the type of the map key. Your map contains classes as keys, and you're trying to pass an object instance to it. Changing this to object as Any? is not a useful fix, because this call will compile but will always return false. What you need to do instead is to use object.javaClass to get the class of the object.
The weightingTable[c] call is reported as an error because the map does not necessarily contain a value for the key you're passing to it, so the result of the [] operation is nullable. You cannot assign a nullable value to a non-null variable without somehow handling the null case (using a check, an explicit non-null cast or some other option covered in the documentation).
When doing:
myHashMap.get(object)
and getting:
Type inference failed. required: kotlin.Double found kotlin.Double?
even when you already checked with containsKey. You can solve it by using:
myHashMap.getOrElse(key) { defaultValue }

can't set objective-c property from swift

in the header file of an objective-c code there is an integer property
#property int xmBufferSize;
I am trying to set property from swift code by
let sharedExample: AnyObject! = XMPAudioPlayer.instance()
sharedExample.xmBufferSize = 1024
Error I get is
Cannot assign to 'xmBufferSize' in 'sharedExample'
This must be pretty straight forward why I am getting this error?
I recommend removing the AnyObject! annotation and leave the compilator to infer the type to be correct - XMPAudioPlayer. Then you will have the correct type and set the attribute as usual.
Like this:
let sharedExample = XMPAudioPlayer.instance()
sharedExample.xmBufferSize = 1024
In case your instance() method returns AnyObject, which would be highly unfortunate, then I'd recommend casting it like this:
let sharedExample = XMPAudioPlayer.instance() as! XMPAudioPlayer
sharedExample.xmBufferSize = 1024
Since AnyObject does not have the property xmBufferSize, the error occurs. Therefore, you should first cast shareExample to appropriate type.
(e.g., (sharedExample as! YourAwesomeClass).xmBufferSize = 1024)
If you want to set property without type casting, try
sharedExample.setValue(1024, forKey: "xmBufferSize")
It's not typesafe way, but sometimes it's convenient and useful.
In your XMPAudioPlayer interface, the return type of the instance method is id, correct? Change the return type to instancetype and the compiler will correctly infer its type, and the error will be resolved.

What is the method signature when it uses an external param name in Swift

I'm using an NSTimer object in my Swift code, which requires a method signature to be passed to its 'selector' parameter in order to recurrently perform said method. When the method signature does not have an external parameter name i.e.
func timerMethod(internal: String) { ... }
I can pass the timer object this signature as so:
var timer = NSTimer.scheduledTimerWithTimeInterval(1.0,
target: self,
selector: Selector("timerMethod:"),
userInfo: userInfo,
repeats: true)
However, if I give the method a signature with an external parameter name, such as:
func timerMethod(external internal: String) { ... }
I can't figure out how to call the method. I attempted to log it using:
println("\(__FUNCTION__)")
Which logs the following:
timerMethod(external:)
But whenever I try this or any of the following, I receive 'unrecognized selector' exceptions:
timerMethod:
timerMethod:external
timerMethod:external:
timerMethod:(external)
timerMethod:(external:)
timerMethod(external):
Stumped for now. Anybody running into something similar?
It is timerMethodWithExternal: you can test that with object_getClass(t).instancesRespondToSelector(Selector("timerMethodWithExternal:"))
i used following code to introspect
func with(t: Test, inout count : CUnsignedInt) -> UnsafePointer<Method> {
var mc : CUnsignedInt = 0
return class_copyMethodList(object_getClass(t), &count)
}
var i=0
var mc : CUnsignedInt = 0
var t = Test()
var mlist = with(t,&mc)
var n : Int = Int(mc)
for (i=0; i<n;i++) {
println(sel_getName(method_getName(mlist[i])))
}
Although the signature for your method doesn't look correct, in Swift you pass a selector simply as the string name. The Apple documentation:
Because string literals can be automatically converted to selectors,
you can pass a string literal to any method that accepts a selector.
As for the signature of NSTimer.scheduledTimerWithTimeInterval, the Apple documentation states (See NSTimer documentation, Swift info):
The selector should have the following signature: timerFireMethod:
(including a colon to indicate that the method takes an argument). The
timer passes itself as the argument, thus the method would adopt the
following pattern:
func timerFireMethod(timer: NSTimer) { }
When you define your own method as:
func timerMethod(external internal: String) { ... }
then you are not meeting the required signature. The expected call is:
someMethod(timer: ...)
but your call would be:
someMethod(external: ...)
Besides, the argument should be of type NSTimer, not String. You were probably lucky that your first attempt worked.
FWIW, I ran into the same problem and was also able to confirm the proper selector name by inspecting the Xcode-generated header file in the derived data folder for my project.
Just search for your method's name ~/Library/Developer/Xcode/DerivedData and for the original poster's example you would find that the selector to be used is timerMethodWithExternal: (from its Objective-C definition).
I believe this header is generated even for pure Swift projects, the project I tested on had some Objective-C in it though.