How to fetch array of string elements with SwiftyJSON? - swift

I have a JSON that might contain an array of string elements and I want to save it to a variable. So far I did:
import SwiftyJSON
(...)
var myUsers = [""]
if(json["arrayOfUsers"].string != nil)
{
myUsers = json["arrayOfUsers"] //this brings an error
}
The error says:
cannot subscript a value of type JSON with an index of type string
How can I pass this array safely to my variable?

You have to get the array of Strings that SwiftyJSON has prepared when it parsed your JSON data.
I will use if let rather than != nil like you do in your question, and we're going to use SwiftyJSON's .array optional getter:
if let users = json["arrayOfUsers"].array {
myUsers = users
}
If for any reason you get a type error, you can explicitly downcast the SwiftyJSON object itself instead of using the getter:
if let users = json["arrayOfUsers"] as? [String] {
myUsers = users
}
Note that your array of Strings is also not created properly. Do like this:
var myUsers = [String]()
or like hits:
var myUsers: [String] = []
Both versions are equally valid and both create an empty array of strings.

Related

Accessing values in a dictionary containing AnyObject

I have some data I stored into a dictionary which is defined as:
let data = Dictionary<String, AnyObject>()
In this dictionary the value is always a string, but the value can be an array or integer or string. But when I try to access an item in a array in this dictionary, like:
let item = data["key"][0]
It gives me this error:
Cannot subscript value of type "AnyObject"
How should I access that item?
You need to tell the compiler that you're expecting an array:
if let array = data["key"] as? [Int] {
let item = array[0]
}
Without that, the compiler only knows that there MAY be an AnyObject in data["key"] (it might also be nil).

Immutable value error when appending to array within dictionary after downcasting

var someDict = [String:Any]()
someDict["foo"] = ["hello"]
(someDict["foo"] as? [String])?.append("goodbye") // error here
I am trying to add a value to an existing dictionary containing an array. The dictionary also contains other non-array values, so it has to have value type Any. The problem is that, when I do this, I get an error Cannot use mutating member on immutable value of type '[String]'. Some Googling turned up a few references such as this suggesting that arrays within dictionaries are always immutable, but the compiler doesn't complain if I do this:
var someDict = [String:[String]]()
someDict["foo"] = ["hello"]
someDict["foo"]?.append("goodbye")
so I suspect that information is outdated and it's something specific to the downcasting. Is there any way I can get around this without copying and re-assigning the entire dictionary value?
Yes, it is related the the downcasting. Try this instead:
var someDict = [String:Any]()
someDict["foo"] = ["hello"]
if var arr = someDict["foo"] as? [String] {
arr.append("goodbye")
someDict["foo"] = arr
}

How to check if a value is nil or not from a Set<T>

I have a Set and now I'm trying to get an object in a index position:
var testItem: ExpandableCell
if let object = expandableCells[indexPath.row] {
testItem = object as! ExpandableCell
}
But I get an error.
UPDATE:
I just convert from SET to Array my collection class variable and now I have this:
let realItem : ExpandableCell?
if let testItem: AnyObject = expandableCells[indexPath.row] {
realItem = testItem as! ExpandableCell
print(realItem?.title)
}
It compiles without a problem but when i run the code and the index its outside of its boundaries then I get the following error:
So seems that my if let statement is not working.
Any clue?
Set is an unordered collection of unique objects. Because they're unordered, getting them by an Int index makes no sense.
Perhaps you meant to use an Array, an ordered collection of objects. Array doesn't guarantee the uniqueness of its objects, but it does preserver ordering, thus Int indexes make sense.
you can use loop Instead if/let condition
for testItem in expandableCells {
if let realItem = testItem as? ExpandableCell {
print(realItem?.title)
}
}

Create a dictionary out of an array in Swift

I want to create a dictionary out of an array and assign a new custom object to each of them. I'll do stuff with the objects later. How can I do this?
var cals = [1,2,3]
// I want to create out of this the following dictionary
// [1:ReminderList() object, 2:ReminderList() object, 3:ReminderList() object]
let calendarsHashedToReminders = cals.map { ($0, ReminderList()) } // Creating a tuple works!
let calendarsHashedToReminders = cals.map { $0: ReminderList() } // ERROR: "Consecutive statements on a line must be separated by ';'"
map() returns an Array so you'll either have to use reduce() or create the dictionary like this:
var calendars: [Int: ReminderList] = [:]
cals.forEach { calendars[$0] = ReminderList() }
You can also use reduce() to get a oneliner but I'm not a fan of using reduce() to create an Array or a Dictionary.

Cannot invoke 'append' with an argument list of type '(String?!)'

I'm trying to add usernames from Parse in an array to display them in a UITableView, but get an error when I'm appending the usernames to my array.
The error I get is: Cannot invoke 'append' with an argument list of type '(String?!)'
What am I doing wrong?
var usernames = [""]
func updateUsers() {
var query = PFUser.query()
query!.whereKey("username", notEqualTo: PFUser.currentUser()!.username!)
var fetchedUsers = query!.findObjects()
for fetchedUser in fetchedUsers! {
self.usernames.append(fetchedUser.username)
}
}
I solved my problem. I declare the array as an empty array and for unwrap the optional with the following code:
var usernames = [String]()
self.usernames.removeAll(keepCapacity: true)
for fetchedUser in fetchedUsers! {
if let username = fetchedUser.username as String! {
self.usernames.append(username)
}
}
PFUser.username is an optional, and you can't append an optional into a String array in Swift. This is because the optional can be nil, and a String array in Swift only accepts strings.
You need to either force unwrap the optional, or use if-let syntax to add it if it exists.
Force Unwrap
self.usernames.append(fetchedUser.username! as String)
Or if-let
if let name = fetchedUser.username as? String {
self.usernames.append(name)
}
Plus as NRKirby mentions in the comments on your question, you might want to look at initialising the usernames array differently. At the moment the first element is an empty string.