'NSString' is not convertible to 'DictionaryIndex<NSObject, AnyObject>' - swift

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.

Related

Why casting nil value as Any is not considered as nil? [duplicate]

I'm iterating through a dictionary of [String: Any], looking for nils, so I can replace them with NSNull for a JSON write. My precompiler warning is telling me that comparing an Any to a nil will always be false, but I know it contains at least two nils which are never found. Is there a way to check is an Any is nil?
An Optional can be nil. Anything else can never be nil. An Any is not an Optional. Thus there is no point comparing an Any to nil. The test will never succeed.
If you know that these things might be Optionals, you should have typed this as Any?. That is an Optional and can be compared to nil. Here's a simple example:
let s : String? = nil
let any : Any? = s
if any == nil {
print("nil") // nil
}
As you can see, the test succeeds.
(Still, if at all possible, it would be even better to type things more precisely.)
I have solved this using bellow expression:
let filteredResult = dictionary.filter { !(($0.value as AnyObject) is NSNull) }
if(object_getClass(yourVariable)?.description() == "NSNull")
can be one of the way to check.
Objective-c property in swift.
If you're using some objective c property in swift and it says something like "Comparing non-optional value of type 'XYZ' to 'nil' always returns true" you have to make that objective c property to "_Nullable" so that property may not be optional anymore. Like
#property (strong,nonatomic) NSString *_Nullable someString;

Swift is using the wrong subscript overload. How can I get it to use the right one?

I'm writing UI testing code using XCTest. Here is my test method:
func testLandingUI() {
let app = XCUIApplication()
let headerExpectedMessage = "Title"
let headerLabel = app.staticTexts[headerExpectedMessage]
XCTAssert(headerLabel.exists)
}
I'm getting this error:
ExampleUITests.swift:38:19: error: value of type 'Any?' has no member 'exists'
XCTAssert(headerLabel.exists)
^~~~~~~~~~~ ~~~~~~
What's strange about this error is that I expected headerLabel to be of type XCUIElement, not Any?.
XCUIApplication.staticTexts is an XCUIElementQuery, which has a subscript method declared thusly:
open class XCUIElementQuery : NSObject, XCUIElementTypeQueryProvider {
...
open subscript(key: String) -> XCUIElement { get }
...
}
What I believe is happening is the subscript method in XCUIElementQuery is not being selected by Swift's overload resolution. Instead, it's selecting this category on NSObject:
#interface NSObject (MyCategory)
- (id)objectForKeyedSubscript:(NSString*)key;
- (void)setObject:(id)obj forKeyedSubscript:(NSString*)key;
#end
I verified that if I remove that category from my project, the error goes away. Assume that removing that category is not possible (because it's not). Is there any way to get Swift to use the correct subscript method?
Minimal test case that shows the problem: https://www.dropbox.com/s/f0fm5ennco7t2ua/SubscriptCategoryTest.zip?dl=1
(note that the error is in the UI tests, so press command-shift-U to see the error)
EDIT: It looks like the problem only shows up if the category defines setObject:forKeyedSubscript:. Interestingly, I get a slightly different error if both getter and setter are defined vs. just the setter.
Since the compiler is confused, you need to help it....
Given this example:
let example1: Any? = "1"
let example2: Any = "2"
You have two issues (it looks like you have an optional...)
if example1.exists { // won't work - I got your error message
}
if (example2 as AnyObject).exists { // works with a cast
}
I believe if you correct identify the type of the variable it will solve your problem. It is matching the NSObject category only because it didn't match something more specific.

Comparing non-optional Any to nil is always false?

I'm iterating through a dictionary of [String: Any], looking for nils, so I can replace them with NSNull for a JSON write. My precompiler warning is telling me that comparing an Any to a nil will always be false, but I know it contains at least two nils which are never found. Is there a way to check is an Any is nil?
An Optional can be nil. Anything else can never be nil. An Any is not an Optional. Thus there is no point comparing an Any to nil. The test will never succeed.
If you know that these things might be Optionals, you should have typed this as Any?. That is an Optional and can be compared to nil. Here's a simple example:
let s : String? = nil
let any : Any? = s
if any == nil {
print("nil") // nil
}
As you can see, the test succeeds.
(Still, if at all possible, it would be even better to type things more precisely.)
I have solved this using bellow expression:
let filteredResult = dictionary.filter { !(($0.value as AnyObject) is NSNull) }
if(object_getClass(yourVariable)?.description() == "NSNull")
can be one of the way to check.
Objective-c property in swift.
If you're using some objective c property in swift and it says something like "Comparing non-optional value of type 'XYZ' to 'nil' always returns true" you have to make that objective c property to "_Nullable" so that property may not be optional anymore. Like
#property (strong,nonatomic) NSString *_Nullable someString;

Pitfall in Swift Type Casting

I am not totally sure if this the right place to post this, as it is more a pitfall I have found than a question I would ask. (Although I would be very interested if someone could explain the reason why this happens.)
So in my Swift iOS-app I had to use Objective-C Arrays for sorting. I knew for a fact that the NSMutableArray called results would contain only MyObjects. Thus, after sorting I cast it to [MyObject] like this to save it in the variable myArrayVar : [MyObject].
myArrayVar = (results as NSArray) as [MyObject]
This worked fine until I tested it on a release build. There it crashed. What I had to do to fix the crash was this:
if let results = results as Any as? NSArray {
if let results = results as? [MyObject] {
myArrayVar = results
} else { NSLog("the impossible happened.") }
} else { NSLog("the impossible happened.") }
Now we can see that this version cannot crash when the casting goes wrong whereas the first version would. However, the cast does not go wrong as I could verify by never seeing the log message.
So what might be the difference at runtime between these two versions of type casting? Whatever it is I have the feeling it might be a pitfall for others as well.

Recasting 'UnsafePointer<Void>' to 'CFHTTPMessageRef'

I've tried dozens of things to get this right and just can't come up with anything that works. Can anyone tell me what's wrong with the following Swift code:
let incomingRequest: CFHTTPMessageRef? = CFDictionaryGetValue(self.incomingRequests as CFMutableDictionaryRef, unsafeAddressOf(incomingFileHandle!)) as CFHTTPMessageRef
The code above gives the error message: 'UnsafePointer<Void>' is not convertible to 'CFHTTPMessageRef'
I guess what I don't understand is how do I convert an 'UnsafePointer' returned by a Core Foundation function to the pointer type it should be (i.e. CFHTTPMessageRef in this case). How do I find documentation on how to do this. I've read everything I can find, but nothing so far explains how to recast return values to what they should have been in the first place. This has to be documented somewhere, doesn't it?
EDIT
Here's the code I'm having trouble with:
let incomingRequest = CFDictionaryGetValue(self.incomingRequests as CFMutableDictionaryRef, unsafeAddressOf(incomingFileHandle!))
unsafeBitCast(incomingRequest, CFHTTPMessageRef.self)
if (incomingRequest != nil) {
let success: Boolean = CFHTTPMessageAppendBytes(incomingRequest as CFHTTPMessageRef, unsafeAddressOf(data!.bytes) as UnsafePointer<UInt8>, data!.length)
if success { // Do something... }
The CFHTTPMessageAppendBytes call still gives a "Type 'UnsafePointer' does not conform to protocol 'AnyObject'". And the following 'if' check for 'success' complains that "Type 'Boolean' doesn not conform to protocol 'BooleanType'". What the heck is that about? Boolean isn't a Boolean type?
I find the strict type checking of Swift extremely frustrating. So far it is far more difficult to code in than Obj-C, C, or any of the other languages I've used. I'm sure it's because I just don't get it, or haven't found the right documentation, but this is really driving me crazy.
Use unsafeBitCast. As following example:
import Foundation
var x = "1"
var dict : NSMutableDictionary = [x: "2"]
var y = CFDictionaryGetValue(dict as CFMutableDictionaryRef, unsafeAddressOf(x))
let str: NSString = unsafeBitCast(y, NSString.self)
str == "2"
FYI: There is one quora related with unsafeBitCast. http://www.quora.com/Why-does-Swift-not-allow-implicit-type-conversion