Ambiguous use of 'subscript' - NSMutableDictionary - ios

My code worked perfectly in the version of Swift in May 2015, when I programmed the app. When I opened XCode 7.2 today I get an odd error message I can't understand: Ambiguous use of 'subscript'. In total I get this error 16 times in my code, do anyone know what I can change to fix this problem?
if let path = NSBundle.mainBundle().pathForResource("colorsAndAlternatives", ofType: "plist") {
if let dict = NSMutableDictionary(contentsOfFile: path) {
let randomNumber = Int(arc4random_uniform(UInt32(numberOfOptions)))
let correctColor = "#" + String(dict["\(randomNumber)"]![1] as! Int!, radix: 16, uppercase: true) // Ambiguous use of 'subscript'
The correctColor is determined by HEX using this code: https://github.com/yeahdongcn/UIColor-Hex-Swift/blob/master/HEXColor/UIColorExtension.swift

The Swift compiler is much more strict now.
Here, it doesn't know for sure what type is the result of dict["\(randomNumber)"] so it bails and asks for precisions.
Help the compiler understand that the result is an array of Ints and that you can access it alright with subscript, for example:
if let result = dict["\(randomNumber)"] as? [Int] {
let correctColor = "#" + String(result[1], radix: 16, uppercase: true)
}

Here's my attempt to unwrap what's going on:
if let path = NSBundle.mainBundle().pathForResource("colorsAndAlternatives", ofType: "plist") {
if let dict = NSMutableDictionary(contentsOfFile: path) {
let randomNumber = Int(arc4random_uniform(UInt32(numberOfOptions)))
let numberKey = "\(randomNumber)"
if let val = dict[numberKey] as? [AnyObject] { // You need to specify that this is an array
if let num = val[1] as? NSNumber { // If your numbers are coming from a file, this is most likely an array of NSNumber objects, since value types cannot be stored in an NSDictionary
let str = String(num.intValue, radix: 16, uppercase: true) // construct a string with the intValue of the NSNumber
let correctColor = "#" + str
}
}
}
}

Related

swift 3 - ios : convert anyObject to string

How could we convert anyobject to string in swift 3, it's very easy in the older version by using.
var str = toString(AnyObject)
I tried String(AnyObject) but the output is always optional, even when i'm sure that AnyObject is not a optional value.
The compiler suggests that you replace your code with:
let s = String(describing: str)
One other option is available if you have a situation where you want to silently fail with an empty string rather than store something that might not originally be a string as a string.
let s = str as? String ?? ""
else you have the ways of identifying and throwing an error in the answers above/below.
Here's three options for you:
Option 1 - if let
if let b = a as? String {
print(b) // Was a string
} else {
print("Error") // Was not a string
}
Option 2 - guard let
guard let b = a as? String
else {
print("Error") // Was not a string
return // needs a return or break here
}
print(b) // Was a string
Option 3 - let with ?? (null coalescing operator)
let b = a as? String ?? ""
print(b) // Print a blank string if a was not a string
Here's a simple function (repl.it) that will mash any value into a string, with nil becoming an empty string. I found it useful for dealing with JSON that inconsistently uses null, blank, numbers, and numeric strings for IDs.
import Foundation
func toString(_ value: Any?) -> String {
return String(describing: value ?? "")
}
let d: NSDictionary = [
"i" : 42,
"s" : "Hello, World!"
]
dump(toString(d["i"]))
dump(toString(d["s"]))
dump(toString(d["x"]))
Prints:
- "42"
- "Hello, World!"
- ""
Try
let a = "Test" as AnyObject
guard let b = a as? String else { // Something went wrong handle it here }
print(b) // Test
try this -
var str:AnyObject?
str = "Hello, playground" as AnyObject?
if let value = str
{
var a = value as! String
}
OR
var a = str as? String

I am creating String by using String(char) but getting optional value with that, how to remove it?

my output is coming like "Optional(\"A\") but I want only string "A". I have to apply filter on my array by using this character.
let char = selectedSection.characters.last
let str = String(char)
let array = result?.objectForKey("GetClassPeriodList") as! NSArray
let filtered = array.filter {
return ($0["Section_Code"] as! String) == str
}
print(filtered)
As #martin-r says, last gives you an optional because you can not be certain that when you ask for the last character of a collection, you actually end out with a character, what if the collection was empty for instance?
What you can do is unwrap it using if let, so you could write:
if let char = selectedSection.characters.last {
let str = String(char)
let array = result?.objectForKey("GetClassPeriodList") as! NSArray
let filtered = array.filter {
return ($0["Section_Code"] as! String) == str
}
print(filtered)
}
And then you know for certain that your char contains a value which you can continue to work with.
You can read more about optionals here
Hope that helps you.

Gives all of them optional value

Hello i have variables but gives all of them Optional(). How can i resolve them my codes under below.
Json append codes for koltuklar koltuklaridler array under below you can see
for name in json as! [AnyObject] {
let SeatName = name["SeatName"]
let SeatDesignId = name["SeatDesignId"]
self.koltuklar.append("\(SeatName)*\(SeatDesignId)*")
if let blogs = json["SeatDetail"] as? [[String: AnyObject]] {
for blog in blogs {
let TicketTypeId = blog["TicketTypeId"]
let TicketTypeName = blog["TicketTypeName"]
let Amount = blog["Amount"]
self.koltuklaridler.append("\(SeatDesignId)*\(TicketTypeId)*\(TicketTypeName)*\(Amount)*")
}
}
Under below you can see tableview inside codes ( That codes doing open koltuklar index path item after search id inside koltuklaridler and when found take some varibles from it )
var koltuklar = [""]
var koltuklaridler = [""]
if let myStrings:String! = koltuklar[indexPath.row]{
print("\(myStrings!)")
let myStringArrf = myStrings.componentsSeparatedByString("*")
print("\(myStringArrf)")
if let koltukisims:String! = String(myStringArrf[0]) {
cell.koltukName.text = koltukisims
}
print(" STR - \(myStringArrf[1] as String!)")
if let index = koltuklaridler.indexOf(myStringArrf[1] as String!) {
let myStringdetaysecilen = koltuklaridler[index]
print("myStringdetaysecilen \(myStringdetaysecilen)")
}
Also my json file
[
{
"SeatDesignId": 16484,
"SeatName": "A6",
"SaloonId": 148,
"SeatDetail": [
{
"TicketTypeId": 1,
"TicketTypeName": "Okay",
"Amount": 13
}
]
},
Output
Optional("A17")*Optional(16254)*
["Optional(\"A17\")", "Optional(16254)", ""]
STR - Optional(16254)
All variables output Optional i try everything but doesn't fix.
As mentioned in my comments, whenever you use String Interpolation "\(...)" make sure that all optional strings are unwrapped. Values read from dictionaries are always optional.
This code unwraps all optional strings
for name in json as! [[String:AnyObject]] {
guard let SeatName = name["SeatName"] as? String,
SeatDesignId = name["SeatDesignId"] as? Int else {
continue
}
self.koltuklar.append("\(SeatName)*\(SeatDesignId)*")
if let blogs = json["SeatDetail"] as? [[String: AnyObject]] {
for blog in blogs {
if let TicketTypeId = blog["TicketTypeId"] as? Int,
TicketTypeName = blog["TicketTypeName"] as? String,
Amount = blog["Amount"] as? Int {
self.koltuklaridler.append("\(SeatDesignId)*\(TicketTypeId)*\(TicketTypeName)*\(Amount)*")
}
}
}
Edit: I updated the casting to the actual types according to the JSON
Now declare both arrays as empty string arrays.
var koltuklar = [String]()
var koltuklaridler = [String]()
and remove the optional binding in the first line
let myStrings = koltuklar[indexPath.row]
print("\(myStrings)")
...
By the way: Your way to "serialize" the strings with asterisks and deserialize it in the table view is very, very clumsy and inefficient. Use a custom class or struct for the data records.
Your problem is that you are creating a string from values from dict without a if let statement so it returns an optional value:
for name in json as! [AnyObject] {
if let SeatName = name["SeatName"],
let SeatDesignId = name["SeatDesignId"] {
self.koltuklar.append("\(SeatName)*\(SeatDesignId)*")
}
if let blogs = json["SeatDetail"] as? [[String: AnyObject]] {
for blog in blogs {
if let TicketTypeId = blog["TicketTypeId"],
let TicketTypeName = blog["TicketTypeName"],
let Amount = blog["Amount"] {
self.koltuklaridler.append("\(SeatDesignId)*\(TicketTypeId)*\(TicketTypeName)*\(Amount)*")
}
}
}
There is a two way of operate optional.
unwrapped using "!" but in this chances of crash if value is nil.
unwrapped using term call "optional binding" using "if let" condition.
if let var = "assigned your optional variable"{
print(var)
}
You will get your variable without optional.

error using valueForKey in swift

Why do I get an error when I used valueForKey... I am using same trick like in objectiveC ...
In ObjectiveC, the code is
self.strSubscribe =[responseObject[#"subscribe"] valueForKey:#"subscribe_ids"];
In Swift , the code is
self.strSubscribe = responseObject["subscribe"].valueForKey["subscribe_ids"] as! String
I declare the variables like
var arraySubCategory : NSMutableArray! = NSMutableArray()
var strSubscribe:String!
And I tried to access the value from below response
{
subscribe =
{
"subscribe_ids" = "1,14";
}
}
Edit
It works using Amit and Eric's solution but now for following data
{
data = (
{
"subscribe_ids" = "1,14";
}
);
}
let dictionary = responseObject["data"][0] as! Dictionary<String,AnyObject>
self.strSubscribe = dictionary["subscribe_ids"] as! String
OR//
if let dic = responseObject["data"][0] as? [String:String], let ids = dic["subscribe_ids"] {
self.strSubscribe = ids
}
but it gives me error:
could not find member 'subscript'
Swift doesn't know the type of responseObject["subscribe"], you have to help the compiler a bit; for example:
if let dic = responseObject["subscribe"] as? [String:String], let ids = dic["subscribe_ids"] {
self.strSubscribe = ids // "1,14"
}
UPDATE:
It's still the same problem: the compiler doesn't know the type of responseObject["data"], so when you try to access the subscript there's an error (because you know it's a dictionary inside the array, but the compiler doesn't).
One solution is to give the type to the compiler by declaring an array of dictionaries in the if let condition:
if let arr = responseObject["data"] as? [[String:String]], let ids = arr[0]["subscribe_ids"] {
self.strSubscribe = ids
}
Notice that it's [[String:String]] (array of dictionaries), not [String:String] (dictionary).
Write like this.
let dictionary = responseObject["subscribe"] as! Dictionary<String, AnyObject>
self.strSubscribe = dictionary["subscribe_ids"] as! String
Since responseObject["subscribe"] will give a AnyObject? output and AnyObject does not have any member called valueForKey.

strange error with plist file

I have a plist file where I added level info. It is setup as follows: It has a dictionary called patterns, then it has an array called 1, and that array contains n items, which are all dictionaries. These items have the 3 booleans and three numbers. This is my code for reading that info:
func readPlstForBlocks(){
let levelPlist = NSBundle.mainBundle().pathForResource("level\(levelToShow)", ofType: "plist")
let levelData = NSDictionary(contentsOfFile: levelPlist!) as NSDictionary!
let patterns = levelData["patterns"] as! NSDictionary
let firstPat = patterns["1"] as! NSArray
for item in firstPat {
let i = item["x"]?!.floatValue
let j = item["y"]?!.floatValue
let movingUpwards = item["movingUpwards"] as! Bool
let movingSidewards = item["movingSidewards"] as! Bool
let spinning = item["spinning"] as! Bool
let typ = item["type"]?!.floatValue
let type = Int16(typ!)
let posx = CGFloat(i!)
let posy = CGFloat(j!)
}
}
Now the lines let movingUpwards = item["movingUpwards"] as! Bool
let movingSidewards = item["movingSidewards"] as! Bool
let spinning = item["spinning"] as! Bool gives me a strange error, saying that i am casting from SKNode to bool and it always fails. That totally confuses me, since I have been accessing booleans from other plist with similar code plenty of times and it seemed to work just fine, and secondly, why on earth xcode would think its SKNode? Anyone knows how to solve this?
EDIT:
I am adding the plist file photo:
In general, when writing Swift code, I would recommend using Swift types as much as possible, not Objective-C types. So, where you have this:
let levelData = NSDictionary(contentsOfFile: levelPlist!) as NSDictionary!
let patterns = levelData["patterns"] as! NSDictionary
let firstPat = patterns["1"] as! NSArray
I would write this:
let levelData = NSDictionary(contentsOfFile: levelPlist!) as! [NSObject:AnyObject]
let patterns = levelData["patterns"] as! [NSObject:AnyObject]
let firstPat = patterns["1"] as! [[NSObject:AnyObject]]
Now, if we get that far without crashing, Swift knows that firstPat is an array of dictionaries, which is much more than you were telling it before. This means that for item in firstPat can correctly type item as a dictionary. And that, in turn, means that you can subscript it and extract values by key:
for item in firstPat {
let i = item["x"] as! Float
let j = item["y"] as! Float
let movingUpwards = item["movingUpwards"] as! Bool
// ...
}
None of that is "good" code; the forced casts are dangerous. In real life, you should be unwrapping / casting safely the whole way down. But I think this will give you a more coherent approach up front.

Resources