Could not cast value of type 'Swift.Array<Swift.String>' (0x61000028bb50) to 'Swift.String' (0x10cbd0ae0)

I have a program that does an initial search of users then populates a table. There are two buttons within the table to accept the users request and another to deny, these buttons call an insert function that inputs the results in the database. The array results are being passed to the function but I'm getting an error of 'Could not cast value of type 'Swift.Array' (0x61000028bb50) to 'Swift.String' (0x10cbd0ae0)' on the following line of code:

  self.insertShot("No", (gname as? Any as! String as AnyObject))

The gname variable is declared as follows:

var gname = String

Here is the code that is getting the array data:


for i in 0 ..< self.guest.count { 
let ava = self.guest[i]["ava"] as? String 
let gname = self.guest[i]["username"] as? String 
let age = (NSString(format: "%@", self.guest[i]["age"] as! CVarArg) as String) 
let city = self.guest[i]["city"] as? String 
let state = self.guest[i]["state"] as? String 
let url = NSURL(string: ava!)! 
self.avas.append(image) 
self.gname.append((gname as AnyObject) as! String) 
self.tableView.reloadData()

Accepted Reply

so guest is OK


probably, when you call insertShot("No", gname)

gname is not defined at all


In your mind, where has gname be initialized in your code when you call insertShot("No", gname) ?


Are you sure that gname scope is correct ?

You define

let gname = self.guest[i]["username"] as? String

but this gname does not exist anymore when you leave the loop where it is defined.


So, to ease debugging :

- find where gname is defined a property of the controller

- change its name by gnameGlobal


You will immediately see where there are undefined gnames : you will get a compiler error ; replace by gnameGlobal


Having a different name will avoid confusion with other declarations as let gname =

So don't change gname in those parts.

Replies

Can you show the code for insertShot ? What are the calling parameters


In anycase, the expression

(gname as? Any as! String as AnyObject)

is uselessly complex (and wrong).


gname is a String: no need to cast to Any to cast later as String

You need to clarify a few more things:


  • How your `insertShot` is declared?
  • Where does the line `self.insertShot("No", (gname as? Any as! String as AnyObject))` exist? (You should show whole method including the line.)


Better show also:


  • The declaration of `self.guest` and `self.gname`.
  • Whole code of the method including the lines "getting the array data".

Here is the remaining code:

InsertShots function

public func insertShot(_ rating : String,_ gname : AnyObject) {

let reviewer = user?["username"] as! String


let url = URL(string: "http://URL TO PHP FILE)

var request = URLRequest(url: url)

request.httpMethod = "POST"


let param = [

"user" : reviewer,

"revieweduser" : gname,

"rating" : rating

] as [String : Any]


let boundary = "Boundary-\(UUID().uuidString)"

request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")


request.httpBody = createBodyWithParams(param as? [String : String], boundary: boundary)

URLSession.shared.dataTask(with: request) { data, response, error in

DispatchQueue.main.async(execute: {

if error == nil {

do {


let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary

guard let parseJSON = json else {

print("Error while parsing")

return

}


let message = parseJSON["users"]


if message != nil {


_ = self.navigationController?.popViewController(animated: true)

}

} catch {

/

DispatchQueue.main.async(execute: {

let message = "\(error)"

appDelegate.infoView(message: message, color: colorSmoothRed)

})

return

}

} else {

/

DispatchQueue.main.async(execute: {

let message = error!.localizedDescription

appDelegate.infoView(message: message, color: colorSmoothRed)

})

return

}

})

}.resume()

return

}


func createBodyWithParams(_ parameters: [String: String]?, boundary: String) -> Data {

let body = NSMutableData();

if parameters != nil {

for (key, value) in parameters! {

body.appendString("--\(boundary)\r\n")

body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")

body.appendString("\(value)\r\n")

}

}

return body as Data

}


IBActions to call insertShot

@IBAction func noBtn_clicked(_ sender: UIButton) {

insertShot("No", (gname as? String as AnyObject))

/

}

@IBAction func yesBtn_clicked(_ sender: UIButton, users: AnyObject) {

if let gname = self.gnames.first { self.insertShot("Yes", gname) }

}

Thanks I've added the remaining code.

Thanks, I've added the remaining code.

Here is the remaining code:

InsertShots function

public func insertShot(_ rating : String,_ gname : AnyObject) {

let reviewer = user?["username"] as! String


let url = URL(string: "http://URL TO PHP FILE)

var request = URLRequest(url: url)

request.httpMethod = "POST"


let param = [

"user" : reviewer,

"revieweduser" : gname,

"rating" : rating

] as [String : Any]


let boundary = "Boundary-\(UUID().uuidString)"

request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")


request.httpBody = createBodyWithParams(param as? [String : String], boundary: boundary)

URLSession.shared.dataTask(with: request) { data, response, error in

DispatchQueue.main.async(execute: {

if error == nil {

do {


let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary

guard let parseJSON = json else {

print("Error while parsing")

return

}


let message = parseJSON["users"]


if message != nil {


_ = self.navigationController?.popViewController(animated: true)

}

} catch {

/

DispatchQueue.main.async(execute: {

let message = "\(error)"

appDelegate.infoView(message: message, color: colorSmoothRed)

})

return

}

} else {

/

DispatchQueue.main.async(execute: {

let message = error!.localizedDescription

appDelegate.infoView(message: message, color: colorSmoothRed)

})

return

}

})

}.resume()

return

}


func createBodyWithParams(_ parameters: [String: String]?, boundary: String) -> Data {

let body = NSMutableData();

if parameters != nil {

for (key, value) in parameters! {

body.appendString("--\(boundary)\r\n")

body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")

body.appendString("\(value)\r\n")

}

}

return body as Data

}


IBActions to call insertShot


@IBAction func noBtn_clicked(_ sender: UIButton) {

insertShot("No", (gname as? String as AnyObject))

/

}

@IBAction func yesBtn_clicked(_ sender: UIButton, users: AnyObject) {

if let gname = self.gnames.first { self.insertShot("Yes", gname) }

}

We do not see the code yet.


You should copy the code in the forum as text, not as an image.

Why do you declare :


public func insertShot(_ rating : String, _ gname : AnyObject)


and not simply:


public func insertShot(_ rating : String, _ gname : String)


In addition, keeping the label would help you in the future.


In IBAction func noBtn_clicked, you should then write simply


    @IBAction func noBtn_clicked(_ sender: UIButton) {
        insertShot("No", gname)
    }



Tell if it works with this.

I'm getting a 'fatal error: unexpectedly found nil while unwrapping an Optional value' error because gname is still nil. The buttons are working fine just the array values are not getting passed to the function. I tried 'insertShots.first("No", gname) and it worked by giving the first value of the array but I need the value associated with each row of the table. Let me know if that makes sense.

Please, be precise, it is really difficult to see exactly what you mean.


Where exactly do you get the error ? Show it in context, so that we can see how each variables are defined.

My apologies Claude31, hopefully this explanation is clearer.

I am getting a fatal error: unexpectedly found nil while unwrapping an Optional value on line 3 of the snippet below. This line is calling the InsertShot function and using the data from the search array. When I hardcode the values the functinality works fine so I know the buttons and insert function work. The issue is gname is constantly nil when running the code.

    @IBAction func noBtn_clicked(_ sender: UIButton) {

        insertShot("No", gname)

}


gname is defined as a String and should be pulling the data from the array for the associates row in the table.

    var gname:String!

gname should be populated from the array that is pulled from the PHP file and being parsed via JSON. I've printed the results to ensure there's not issue on the PHP side. The array seems to be working fine but the individual values of the array aren't getting passed just the entire array. Line 31 below is where gname is being defined, but that value isnt getting out of the for loop so it can be used when InsertShot is called on the above snippet. Here is where the data is parsed and the array code with comments. :

                     //  // declare json var to store $returnArray info we got from php
                        let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
                 
                        // // clean up
                        self.guest.removeAll(keepingCapacity: false)
                        self.avas.removeAll(keepingCapacity: false)
                        self.tableView.reloadData()
                 
                        //    // delcare new secure var to store json
                        guard let parseJSON = json else {
                            print("Error while parsing")
                            return
                        }
                 
                        // // declare new secure var to store $returnArray["users"] from PHP
                        guard let parseUSERS = parseJSON["users"] else {
                            print(parseJSON["users"] ?? [NSDictionary]())
                            return
                        }
                 
                        // // append $returnArray["users"] to self.guest var
                        self.guest = parseUSERS as! [AnyObject]
                        print(self.guest)
                        /
                        for i in 0 ..< self.guest.count {
                     
                            /
                            let ava = self.guest[i]["ava"] as? String
                     
                            let gname = self.guest[i]["username"] as? String
                            let url = NSURL(string: ava!)! /
                            let imageData = try? Data(contentsOf: url as URL)
                            let image = UIImage(data: imageData!)! /
                     
                            self.avas.append(image)
                            self.gnames.append(gname! as String)
                            self.tableView.reloadData()
                     
                            print("print 9", gname)
                        }

You have :


let gname = self.guest[i]["username"] as? String


So, if self.guest[i]["username"] is not found, gName is nil.


What do you get in log with line 23 ?

                        print(self.guest)


You should instrument your code to see what's hapenning :

                        for i in 0 ..< self.guest.count {
                   
                           print("self.guest[i])", self.guest[i])     // you will see if ava and username are defined
                            let ava = self.guest[i]["ava"] as? String
                   
                            let gname = self.guest[i]["username"] as? String
                            let url = NSURL(string: ava!)!


Can you show how guest is built ? It should be an array of dictionary in your code.

Thanks Claude for responding. I actually removed all the print statements when I pasted the code so it didnt look too confusing. Here are the answers to your questions:


After print(self.guest) the log gives me the full array of data.


I added in print("self.guest[i])", self.guest[i]) as you suggested and it gives me the individual rows of the arrays and none of them were nil.


Here is how guest is built:

            DispatchQueue.main.async(execute: {
               
                if error == nil {
                   
                    do {
                        /
                        let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
                       
                        /
                        self.guest.removeAll(keepingCapacity: false)
                        self.avas.removeAll(keepingCapacity: false)
                        self.tableView.reloadData()
                       
                        /
                        guard let parseJSON = json else {
                            print("Error while parsing")
                            return
                        }
                       
                        /
                        guard let parseUSERS = parseJSON["users"] else {
                            print(parseJSON["users"] ?? [NSDictionary]())
                            return
                        }
                       
                        /
                        self.guest = parseUSERS as! [AnyObject]

In each item guest[i], do you have a "username" value (take care to uppercase)


Would you mind showing the print(self.guest) result ?


It is not clear from

guard let parseUSERS = parseJSON["users"] else {

print(parseJSON["users"] ?? [NSDictionary]())

return

}


how the "username" value is loaded

Here is the output of printing the array.


self.guest[i]) {

age = 47;

ava = "http:/

id = 2;

user = tester1;

username = Tester1;

}