0

I need to cast the below response from my server as [UserResult] but I cannot get it to work??

What am I doing wrong?

 func userSearch(keyword: String, completion: @escaping (Result<[UserResult], ResponseError>) -> Void ) {
        socket.emit("userSearch", keyword)
        
        socket.on("userFound") { ( data, ack) in
               print(data) // prints below NSArray
            if !data.isEmpty {
                if let response = data as? [UserResult] {
                   print("USERS \(response)") // WILL NOT WORK?
                   completion(.success(response))
                }
            } else {
                completion(.failure(.badRequest("No users found")))
            }
        }
    }

Data from server

 [<__NSArrayM 0x60000040e5b0>(
{
    profileUrl = "www.address1.com";
    username = chrissmith;
},
{
    profileUrl = "www.address2.com";
    username = johnsmith;
},
{
    profileUrl = "www.address3.com";
    username = alicesmith;
}
)
]

UserResult Model

struct UserResult: Decodable {
    let username: String
    let profileUrl: String
}


Jake Smith
  • 580
  • 3
  • 11
  • It depends on how your dataset is encoded. Just saying "Data from server" is not going to help. – El Tomato Dec 07 '21 at 02:50
  • The data looks a bit strange -- URLs have quotes, but usernames do not. – tromgy Dec 07 '21 at 03:02
  • An `NSArray` cannot have `struct UserResult` instances in it, since `NSArray` can only hold objects. You need to look at where `data` is coming from and work out what is really in the array so you can cast it to the right thing – Paulw11 Dec 07 '21 at 07:44
  • are you using Socket.IO-Client-Swift library ? https://cocoapods.org/pods/Socket.IO-Client-Swift – Mr.SwiftOak Dec 07 '21 at 12:26
  • Yes I am using the Socket.IO Client Swift Library – Jake Smith Dec 07 '21 at 14:40
  • I guess you have a `NSArray` of `NSDictionary`. So if your lib doesn't provide more method, it should be: `let response = data.compactMap { aValue -> UserResult? in guard let aDict = aValue as? [String: Any] else { return nil }; guard let userName = aDict["username"] as? String, let profileUrl = aDict["profileUrl"] as? String else { return nil }; return UserResult(username: userName, profileUrl: profileUrl) }` – Larme Dec 08 '21 at 08:49

1 Answers1

0

Well you are using Socket.IO library and specifically method

    socket.on(clientEvent: .connect) {data, ack in
    ...
}

defined as

@discardableResult
open func on(clientEvent event: SocketClientEvent, callback: @escaping NormalCallback) -> UUID

using typealias:

public typealias NormalCallback = ([Any], SocketAckEmitter) -> ()

So basically at the and you are being returned data of type [Any] according to documentation. Since you do not know what is inside your data it is better for you to unwrap objects in your array one by one (instead casting it directly to [UserResult]) and try to find out what Type there are by comparing to some set of known types as some of answers from this question suggest. I would start with verifying the data structure with example code below , and only move on with casting to various type afterwards: Lets assume example data1 is your data:

let dict1 = ["profileUrl":"www.address1.com","username":"chrissmith"]
let data1: NSArray = [dict1]
//printed data1:
//  (
//        {
//        profileUrl = "www.address1.com";
//        username = chrissmith;
//    }
//  )

    if data1[0] as? [String:String] != nil {
    print("We found out that first object is dictionary of [String:String]!")
    }
    else if  data1[0] as? Dictionary<NSObject, AnyObject> != nil {
    print("We found out that first object is dictionary of mixed values!")
   } else {
    print("We found out that first object has different data structure")
   }

Hopefully this answer was at least a little bit helpfull, even though not providing direct easy solution for your problem.

Mr.SwiftOak
  • 1,469
  • 3
  • 8
  • 19
  • Since the explanation fits, a way to do it would be `let response = data.compactMap { aValue -> UserResult? in guard let aDict = aValue as? [String: Any] else { return nil }; guard let userName = aDict["username"] as? String, let profileUrl = aDict["profileUrl"] as? String else { return nil }; return UserResult(username: userName, profileUrl: profileUrl) }`. – Larme Dec 08 '21 at 08:50