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

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.

Related

Array keeps coming back as Nil from Parse

I'm trying to determine if a Parse value has been defined and then if the object has a value assign the Array to my arr variable.
But it keeps coming back as nil. And yes, there is a value inside blockedUsers which is a Parse Array.
if let blockedUser2 = currentUser?["blockedUsers"] as! [String]{
let arr = currentUser?["blockedUsers"] as! [String]
print(arr)
}
You don't need arr: if the condition is matched, you can access blockedUser2. You are already unwrapping it safely with the if let declaration.
About your issue... could you provide some more code? Where do you get your currentUser array from?

Swift Dictionary access value through subscript throws Error

Accessing a Swift Dictionary value through subscript syntax is gives error Ambiguous reference to member 'subscript'
Here is the code
class Model {
struct Keys {
static let type :String = "type" //RowType
static let details :String = "details"
}
var type :RowType = .None
var details :[Detail] = []
init(with dictionary:Dictionary<String, Any>) {
if let type = dictionary[Keys.type] as? String {
self.type = self.rowTypeFromString(type: type)
}
if let detailsObj = dictionary[Keys.details] as? Array { //Error : Ambiguous reference to member 'subscript'
}
}
}
if i remove the type casting as? Array at the end of optional-binding it compiles fine
I am expecting the value of details key to be an Array, I know that i can use [String,Any] instead of Dictionary<Key, Value>, What is causing the issue ?
Array doesn't work like NSArray, you explicitly need to tell what type your array is storing.
If you want to store Detail objects in it, the proper syntax is Array<Detail> or simply [Detail]
if let detailsObj = dictionary[Keys.details] as? Array<Detail> {
}
Issue is solved by explicitly specifying the Type of objects the array contains, In my case it was Array<[String:Any]>
if let detailsObj = dictionary[Keys.details] as? Array<[String:Any]> { //we should also specify what type is present inside Array
}
Credits: #Hamish, #Dávid Pásztor
Thanks!

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 fetch array of string elements with SwiftyJSON?

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.

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

What is wrong here and how to solve this problem?
struct Venue {
let building: String
var rooms: [String]?
}
func addRoom(building: String, room: String) {
if let venueIndex = find(venues.map {$0.building}, building) {
venues[venueIndex].rooms.append(room) //Cannot invoke 'append' with an argument list of type'(String)'
}
}
var venues: [Venue] = [...]
The problem is that venues[venueIndex].rooms is not a [String] but a [String]?. Optionals don’t have an append method – the value wrapped inside them might, but they don’t.
You could use optional chaining to do the append in the case where it isn’t nil:
venues[venueIndex].rooms?.append(room)
But you may instead want to initialize rooms to an empty index instead when it is nil, in which case you need to do a slightly messier assignment rather than an append:
venues[venueIndex].rooms = (venues[venueIndex].rooms ?? []) + [room]
However, it is worth asking yourself, does rooms really need to be optional? Or could it just be a non-optional array with a starting value of empty? If so, this will likely simplify much of your code.