Swift optional chaining with NSDictionary - syntax

Please help to remake this
if let field = parent_obj?.getFieldForCode(code) {
if let stored_value = field["value"] as? String {
into optional chaining syntax in single line. I tried to do it like this:
let stored_value = parent_obj?.getFieldForCode(code)?["value"] as? String
and got an error:
Type 'String' does not conform to protocol 'NSCopying'
This is my function header:
func getFieldForCode(code: String) -> NSDictionary?
Is it possible? I ask it because any time I work with NSArrays and NSDictionaries my code looks terrible:
if let code = self.row_info["code"] as? String {
if let value_field = self.row_info["value_field"] as? String {
if let field = parent_obj?.getFieldForCode(code) {
if let stored_value = field["value"] as? String {
if let fields = self.fields_set{
if let current_value = fields[indexPath.row][value_field] as? String {
Any advices?

You can't cast it directly to a String because you're pulling it from an NSDictionary and, like the error says, String doesn't conform to NSCopying. However, String is bridged to NSString, and NSString does conform to NSCopying. So, with a little bit of casting/bridging trickery, you can make it work like this:
let stored_value: String? = parent_obj?.getFieldForCode(code)?["value"] as? NSString
Note: If you're using this in an optional binding (which it looks like you want to), don't forget to drop the ? from stored_value's type declaration:
if let stored_value: String = parent_obj?.getFieldForCode(code)?["value"] as? NSString {
/* ... */
}

Related

SceneKit Swift3 compiler-error

I'm trying to run animated "DAE" model in SceneKit:
let url = Bundle.main.url(forResource: "art.scnassets/Player(walking)", withExtension: "dae")
let sceneSource = SCNSceneSource(url: url!, options: [SCNSceneSource.LoadingOption.animationImportPolicy: SCNSceneSource.AnimationImportPolicy.playRepeatedly] )
let animationIds: NSArray = sceneSource?.identifiersOfEntries(withClass: CAAnimation)
for eachId in animationIds {
let animation: CAAnimation = (sceneSource?.entryWithIdentifier(eachId as! String, withClass: CAAnimation.self))!
animations.add(animation)
}
character?._walkAnimations = animations
But compiler It throws on the line:
let animationIds: NSArray = sceneSource?.identifiersOfEntries(withClass: CAAnimation)
and writes an error:
Cannot convert value of type '[String]?' to specified type 'NSArray'
Please help me to fix that problem.
Thanks in advance.
Why you are converting [String]? to NSArray and then convert each element to String again, no need of it simply use Swift native Array and wrapped the optional value with if let or guard let.
guard let animationIds = sceneSource?.identifiersOfEntries(withClass: CAAnimation) else {
return
}
for eachId in animationIds {
if let animation = sceneSource?.entryWithIdentifier(eachId, withClass: CAAnimation.self) {
animations.add(animation)
}
}
character?._walkAnimations = animations

How to fix `Ambiguous use of 'subscript'` every time?

I'm using this class that was written in Swift 1.2 and now I want to use it with Swift 2.0.
I get an error: Ambiguous use of 'subscript' # let artist = result["name"] as! String
} else if let jsonArtists = jsonResult["artists"] as? NSDictionary {
if let results:NSArray = jsonArtists["items"] as? NSArray {
dispatch_async(dispatch_get_main_queue(), {
self.searching = false
var suggestionResults: [spotifySearchResult] = []
for result in results {
let artist = result["name"] as! String
var sugresult = spotifySearchResult()
sugresult.artist = artist
if !suggestionResults.contains(sugresult) {
suggestionResults.append(sugresult)
}
}
handler(suggestionResults)
})
}
}
}
I tried different fixes such as let artist = (result["name"] as! String) or let artist = (result["name"] as! String) as! String
But nothing worked.
I know that the question was already post 4 times but, I can't find anyone explaining how to fix it in every case, only case by case.
Can someone explain me how to investigate to fix it? Not just only a fix for my case. I would prefer fix it by myself with your hints!
BTW what does mean subscript? Is subscript the thing between quotation mark? IMHO the error message is a bit vague...
EDIT:
class spotifySearchResult : NSObject {
var artist=""
var track=""
var duration=0
var spotifyURL = NSURL()
var spotifyURI = NSURL()
override func isEqual(theObject: AnyObject?) -> Bool {
if let myObject = theObject as? spotifySearchResult {
return (myObject.artist.uppercaseString == self.artist.uppercaseString && myObject.track.uppercaseString == self.track.uppercaseString)
}
return false
}
}
Subscription means to use the shorter syntax item["key"] for item.objectForKey["key"]
results seems to be an array of dictionaries so I suggest to cast down to a more specific type
if let results = jsonArtists["items"] as? [[String:AnyObject]] {
or even, if all values are guaranteed to be strings
if let results = jsonArtists["items"] as? [[String:String]] {

Swift Parse.com unable to retrieve object

So I am trying to get a String that is saved within an object from Parse.com. Here is the code that I am using to do so:
var query: PFQuery = PFQuery(className: "Replys")
query.getObjectInBackgroundWithId("ipmdKB0N1N") {
(object: PFObject?, error: NSError?) -> Void in
if error == nil && object != nil {
println(object)
self.replyField.text = object["Replys"]
} else {
println(error)
}
}
I want to make this string the text of the label called "replyField" but when I try to do that, Xcode gives an error like "Cannot assign value "AnyObject?" to type "String?"" Even when I add as! String, it still gives a similar (though not exactly the same) error. Any ideas why?
You should unwrap optional of object. Such as object!["Replys"] or object?["Replys"]
Like below:
self.replyField.text = object!["Replys"] as! String
or
self.replyField.text = object?["Replys"] as! String
let replysString = object["Replys"] as! NSString
self.replyField.text = replysString as String

Type 'AnyObject' does not conform to protocol 'SequenceType'

func loadThumbnails() {
let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let documentsDirectory:NSString = paths[0] as NSString
var error:NSError?
let fileManager = NSFileManager()
let directoryContent:AnyObject = fileManager.contentsOfDirectoryAtPath(documentsDirectory, error: &error)!
thumbnails = [QSPhotoInfo]()
for item:AnyObject in directoryContent {
let fileName = item as NSString
if fileName.hasPrefix(kThumbnailImagePrefix) {
let image = loadImageFromDocumentsDirectory(fileName)
var photoInfo = QSPhotoInfo()
photoInfo.thumbnail = image;
photoInfo.thumbnailFileName = fileName
thumbnails += photoInfo
}
}
}
the compile error is below:
Type 'AnyObject' does not conform to protocol 'SequenceType'
what does this menas?
who can help me ,thks a lot!!!!
Apple states in The Swift Programming Language:
The for-in loop performs a set of statements for each item in a range,
sequence, collection, or progression.
Right now, directoryContent is just conforming to protocol AnyObject, so you can't use for loops over it. If you want to do so, you have to do something similar to the following:
for item in directoryContent as [AnyObject] {
//Do stuff
}
contentsOfDirectoryAtPath returns an NSArray, whereas you are casting it to AnyObject. The solution is to cast it to either [AnyObject]? or NSArray:
let directoryContent: [AnyObject]? = fileManager.contentsOfDirectoryAtPath(documentsDirectory, error: &error)
or
let directoryContent: NSArray? = fileManager.contentsOfDirectoryAtPath(documentsDirectory, error: &error)
Then use an optional binding before the for loop:
if let directoryContent = directoryContent {
for item:AnyObject in directoryContent {
Looking at the contentsOfDirectoryAtPath documentation, it states it always returns an array - so what said above can be reduced to unwrapping the return value to either a swift or objc array, with no need to use the optional binding:
let directoryContent: [AnyObject] = fileManager.contentsOfDirectoryAtPath(documentsDirectory, error: &error)!
or
let directoryContent: NSArray = fileManager.contentsOfDirectoryAtPath(documentsDirectory, error: &error)!

Creating NSData from NSString in Swift

I'm trying to ultimately have an NSMutableURLRequest with a valid HTTPBody, but I can't seem to get my string data (coming from a UITextField) into a usable NSData object.
I've seen this method for going the other way:
NSString(data data: NSData!, encoding encoding: UInt)
But I can't seem to find any documentation for my use case. I'm open to putting the string into some other type if necessary, but none of the initialization options for NSData using Swift seem to be what I'm looking for.
In Swift 3
let data = string.data(using: .utf8)
In Swift 2 (or if you already have a NSString instance)
let data = string.dataUsingEncoding(NSUTF8StringEncoding)
In Swift 1 (or if you have a swift String):
let data = (string as NSString).dataUsingEncoding(NSUTF8StringEncoding)
Also note that data is an Optional<NSData> (since the conversion might fail), so you'll need to unwrap it before using it, for instance:
if let d = data {
println(d)
}
Swift 4 & 3
Creating Data object from String object has been changed in Swift 3. Correct version now is:
let data = "any string".data(using: .utf8)
In swift 5
let data = Data(YourString.utf8)
Here very simple method
let data = string.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
Swift 4
let data = myStringVariable.data(using: String.Encoding.utf8.rawValue)
// Checking the format
var urlString: NSString = NSString(data: jsonData, encoding: NSUTF8StringEncoding)
// Convert your data and set your request's HTTPBody property
var stringData: NSString = NSString(string: "jsonRequest=\(urlString)")
var requestBodyData: NSData = stringData.dataUsingEncoding(NSUTF8StringEncoding)!
To create not optional data I recommend using it:
let key = "1234567"
let keyData = Data(key.utf8)
Convert String to Data
extension String {
func toData() -> Data {
return Data(self.utf8)
}
}
Convert Data to String
extension Data {
func toString() -> String {
return String(decoding: self, as: UTF8.self)
}
}
Swift 4.2
let data = yourString.data(using: .utf8, allowLossyConversion: true)

Resources