(SKNode) not convertible to string (it was working with old xCode) - ios

In my apps I was using this piece of code and it worked perfectly:
var data3: NSArray = [] //1
for gg in data3{ //2
var hh:String = gg["percentage"] as String //3
perchomerec = hh.toInt()! //4
}
Now I updated my xCode and OSx version and now this same piece of code gives this error (on line //3):
[SKNode] is not convertible to String
What do I have to change?

Since Swift 1.2 as operator can only be used for upcasting. When downcasting, you should use as! or as? (detailed description can be found e.g. in The Swift Programming Language).
var hh:String = gg["percentage"] as! String

data3 seem to be of type [[String:Int]] based on your responses on my comments.
So by changing NSArray to [[String:Int]] or just simply removing NSArray completely and letting Swift determine the type by itself.
I guess your question is in pseudo-code so my guess is how you set that data3's data:
let data3 = [["percentage" : 33]] // Swift will determine this type to: [[String:Int]]
for gg in data3 { // gg will become [String:Int]
perchomerec = gg
}
Or if you still want the NSArray type then to cast gg in a for loop you have to cast the array itself:
for gg in data3 as! [[String:Int]]
Edit
If the array changes then it has to be an NSArray or [AnyObject] and then you have to test to cast for every possible type.
for gg in data3 {
if let dict = gg as? NSDictionary {
if let str = dict["percentage"] as? String, nr = str.toInt() {
perchomerec = nr
}
else if let nr = dict["percentage"] as? Int {
perchomerec = nr
}
}
}

It sounds like you need to use ! or ?, although from Jakub Vano's answer it sounds like using optional unwrapping would be more suitable for your code. If you don't expect hh to not be a String or not be nil then I also suggest you check your code elsewhere.
var data3: NSArray = []
for gg in data3 {
if let h = hh as? String {
perchomerec = h.toInt()!
}
}

Related

Formatting NSArray for Swift

I have trouble formatting the NSArray
let temp = json.value(forKeyPath: "data.current_condition.temp_F") as Any
DispatchQueue.main.async {
self.setWeather(temp: temp as! NSArray )
}
func setWeather( temp: NSArray) {
TempLabel.text = "\(temp)"
When I run the program TempLabel only shows " ( " because it's in NSArray form. I am not sure how do I get rid of "(".
Using the description of the object to show it on the UI is quite fragile, and could change anytime internally in iOS.
What I would try instead is to cast the result of your json value into Swift types. In your case [Int] should work. Then use one of the collection methods to convert the Int array to String.
Try something like this:
let temp = json.value(forKeyPath: "data.current_condition.temp_F") as! [Int]
TempLabel.text = temp.map({ "\($0)" }).joined(separator: ", ")

create a dictonary with for loop in swift

I just want to create a dictionary with the help of for loop
sample code :
var counter: Int = 1;
var pageCountDict = [String:Any]();
for filterCount in counter..<6
{
if let count = "page_\(filterCount)_vtime" as? String
{
pageCountDict = [count: timeInterval_Int];
}
}
print(pageCountDict);
This print command give me only last value of forloop
I just want all the value of this variable pageCountDict in a dictonary
The way to assign to a dictionary is first use the subscript and assign the value to it:
pageCountDict[YourKey] = YourValue
Also, you can see many examples and explanations in Apple documentation regarding dictionaries.
With each loop, you are replacing the dictionary with one that contains only one element. What you want to do is this :
pageCountDict[count] = timeInterval_Int
Also, you shouldn't need the as? String part. This should be sufficient :
for filterCount in counter..<6
{
pageCountDict[count] = "page_\(filterCount)_vtime"
}
var pageCountDict = [String:Any]()
You can add values to this dictionary by merging previous contents and new data as follows...
let counter: Int = 1
var pageCountDict = [String:Any]()
for filterCount in counter..<6
{
let value = 9
let count = "page_\(filterCount)_vtime" //'if' is not needed as it is always true
pageCountDict.merge([count: timeInterval_Int], uniquingKeysWith:{ (key, value) -> Any in
//assign value for similar key
timeInterval_Int
})
}
print(pageCountDict)`

Sort value in dictionary that resides within an array

I have an Array: var messageArray = [AnyObject]() and in that Array there is a single tuple that contains Dictionaries with 10 key/value paires (9 of them not important for the sort): var messageDetailDict = [String: AnyObject]()
Getting and setting those values all work correctly, however now I want to sort the Array by 1 of the values (not keys) of the Dictionary.
Example -> The Array has a tuple containing several Dictionaries:
The key in the Dictionary (which is the first element in the Array) is: 'ReceivedAt' which has a value of 21-03-2015
The key in the Dictionary (which is the second element in the Array) is: 'ReceivedAt' which has a value of 20-03-2015
The key in the Dictionary (which is the third element in the Array) is: 'ReceivedAt' which has a value of 15-03-2015
Now the Array should be sorted so that the values of 'ReceivedAt' will be sorted from earliest date, to the last date.
Hope this makes sense, but it's a bit difficult to explain. Thanks!
EDIT >>>>>
This is the println(messageArray) output:
[(
{
ConversationId = "94cc96b5-d063-41a0-ae03-6d1a868836fb";
Data = "Hello World";
Id = "eeb5ac08-209f-4ef0-894a-72e77f01b80b";
NeedsPush = 0;
ReceivedAt = "/Date(1439920899537)/";
SendAt = "/Date(1436620515000)/";
Status = 0;
},
{
ConversationId = "94cc96b5-d063-41a0-ae03-6d1a868836fb";
Data = "Hello World";
Id = "86b8766d-e4b2-4ef6-9112-ba9193048d9d";
NeedsPush = 0;
ReceivedAt = "/Date(1439921562909)/";
SendAt = "/Date(1436620515000)/";
Status = 0;
}
)]
And the received date is converted to a string with the following method (I do think however this is not important, as it is a time interval, and therefore OK to sort):
func getTimeStampFromAPIValue(dateTimeReceived: String) -> String {
let newStartIndex = advance(dateTimeReceived.startIndex, 6)
let newEndIndex = advance(dateTimeReceived.endIndex, -2)
let substring = dateTimeReceived.substringWithRange(newStartIndex..<newEndIndex) // ell
let receivedAtValueInInteger = (substring as NSString).doubleValue
let receivedAtValueInDate = NSDate(timeIntervalSince1970:receivedAtValueInInteger/1000)
//format date
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "dd-MM-yy hh:mm"
var dateString = dateFormatter.stringFromDate(receivedAtValueInDate)
return dateString
}
Since the values of ReceivedAt are timestamps as strings you could apply the following algorithm:
var sortedArray = messageArray.sorted { (dict1, dict2) in
// Get the ReceivedAt value as strings
if let date1String = dict1["ReceivedAt"] as? String,
let date2String = dict2["ReceivedAt"] as? String {
// Compare the date strings to find the earlier of the two
return date1String.compare(date2String) == .OrderedAscending
}
// Couldn't parse the date, make an assumption about the order
return true
}
Try this, change OrderedAscending with OrderedDescending if need in inverse order
messageArray.sortInPlace {
($0["ReceivedAt"] as! NSDate).compare($1["ReceivedAt"] as! NSDate) == .OrderedAscending
}

Swift filter array of strings

I've had troubles filtering array of keywords (strings) in swift ,My code:
self.filteredKeywords=filter(keywords.allValues, {(keyword:NSString) ->
Bool in
let words=keyword as? NSString
return words?.containsString(searchText)
})
As AnyObject can't be subtype of NSString, I'm stuck with this!
[Updated for Swift 2.0]
As NSString is toll-free bridged to Swift String, just avoid the coercions with:
3> ["abc", "bcd", "xyz"].filter() { nil != $0.rangeOfString("bc") }
$R1: [String] = 2 values {
[0] = "abc"
[1] = "bcd"
}
But, if you think allValues aren't strings:
(keywords.allValues as? [String]).filter() { nil != $0.rangeOfString("bc") }
which returns an optional array.
Your filter is over [AnyObject], but your closure takes NSString. These need to match. Also, your result needs to be a Bool, not a Bool?. You can address these simply like this:
self.filteredKeywords = filter(keywords.allValues, {
let keyword = $0 as? NSString
return keyword?.containsString(searchText) ?? false
})
This accepts AnyObject and then tries to coerce it down to NSString. It then nil-coalleces (??) the result to make sure it always is a Bool.
I'd recommend, though, treating keywords as a [String:String] rather than an NSDictionary. That would get rid of all the complications of AnyObject. Then you can just do this:
self.filteredKeywords = keywords.values.filter { $0.rangeOfString(searchText) != nil }
Whenever possible, convert Foundation collections into Swift collections as soon as you can and store those. If you have incoming Foundation objects, you can generally convert them easily with techniques like:
let dict = nsdict as? [String:String] ?? [:]
Or you can do the following to convert them such that they'll crash in debug (but silently "work" in release):
func failWith<T>(msg: String, value: T) -> T {
assertionFailure(msg)
return value
}
let dict = nsdict as? [String:String] ?? failWith("Couldn't convert \(d)", [:])
Swift 4.2 provides a new way to do this:
var theBigLebowski = ["The Dude", "Angry Walter", "Maude Lebowski", "Donny Kerabatsos", "The Big Lebowski", "Little Larry Sellers"]
// after removeAll -> ["The Dude", "Angry Walter", "Donny Kerabatsos", "Little Larry Sellers"]
theBigLebowski.removeAll{ $0.contains("Lebowski")}
print(theBigLebowski)
There is both a problem with GoZoner's answer for certain data types and also a slightly better way to do this. The following examples can show this:
let animalArray: NSMutableArray = ["Dog","Cat","Otter","Deer","Rabbit"]
let filteredAnimals = animalArray.filter { $0.rangeOfString("er") != nil }
print("filteredAnimals:", filteredAnimals)
filteredAnimals: [Dog, Cat, Otter, Deer, Rabbit]
Likely not the set you expected!
However this works fine this way if we don't type animalArray as an NSMutableArray:
let animalArray = ["Dog","Cat","Otter","Deer","Rabbit"]
let filteredAnimals = animalArray.filter { $0.rangeOfString("er") != nil }
print("filteredAnimals:", filteredAnimals)
filteredAnimals: [Otter, Deer]
However I'd recommend using $0.contains() instead of $0.rangeOfString() != nil because it functions in both circumstances and slightly enhances the readability of the code:
let animalArray: NSMutableArray = ["Dog","Cat","Otter","Deer","Rabbit"]
let filteredAnimals = animalArray.filter { $0.contains("er") }
print("filteredAnimals:", filteredAnimals)
filteredAnimals: [Otter, Deer]

How to unwrap NSMutableDictionary.allkeys in optional String Array

I am trying to get all the key values of NSMutableDictionary as String Array. I am using this myNSMutableDictionary.allkeys to get the values as an Array but I cannot find a way to unwrap the key values.
This is what I have tried so far:
for (key, _) in NSMutableDictionary {
println("THIS IS MY NEW KEY\(key)")
}
And I tried this
var myArray:NSArray = myNSMutableDictionary.allKeys
var string:NSString? = uniqueIDArray[0] as? NSString
println("This is unwraped value\(string!)")
And this
var myArray:Array = myNSMutableDictionary.allKeys
println("This is unwraped value\(myArray[0])")
I keep getting the value as Optional("kMSZgoTmiX") instead of kMSZgoTmiX which is the key value I need
Thank you for all your help!
So you've got a dictionary with values that are strings (and keys that are something, assume String):
var dictionaryOfStringValues : [String:String] = /* your dictionary */
And you want to iterate over the contents:
for (key, val) in dictionaryOfStringValues {
// use key and val
}
If you just want the values in a way you can easily iterate over:
var theValues = dictionaryOfStringValues.values
If you insist that theValues be an Array:
var theValuesAsAnArray = Array(dictionaryOfStringValues.values)
If you are starting with an NSMutableDictionary, then convert it at the point where it FIRST ENTERS your Swift code into a Swift Dictionary. Use an as variant to do that. After that, pure Swift.
Like this:
7> for (key, value) in ["a":1, "b":2] {
8. println (key)
9. println (value)
10. }
b
2
a
1
let myNSMutableDictionary = NSMutableDictionary()
myNSMutableDictionary["myKey1"] = 5
myNSMutableDictionary["myKey2"] = 10
myNSMutableDictionary["myKey3"] = 15
let myKeysArrayUnsorted = myNSMutableDictionary.allKeys as [String]
let myValuesArrayUnsorted = myNSMutableDictionary.allValues as [Int]
let keyString = myKeysArrayUnsorted[0] // "myKey2"
let keyValue = myNSMutableDictionary[keyString] as Int // 10
println("This is my first unsorted key \(keyString) = \(keyValue)")
let myKeysArraySorted = (myNSMutableDictionary.allKeys as [String]).sorted(<)
for key in myKeysArraySorted {
println(myNSMutableDictionary[key]!) // 5 10 15
}

Resources