Home > Net >  UICollectionView - Async call in UISwipeAction
UICollectionView - Async call in UISwipeAction

Time:01-18

i am learning to build collectionView the modern way for a few weeks now, and i am constantly facing issue to overcome and solve, but i am making no progress with this one here at all..

var layoutConfig = UICollectionLayoutListConfiguration(appearance: .plain)
        layoutConfig.trailingSwipeActionsConfigurationProvider = { indexPath in
            
            let commentIDString = self.dataSource.itemIdentifier(for: indexPath)?.commentID
            let commentID = Int32(commentIDString ?? 0)
            
            let action = UIContextualAction(style: .destructive, title: "", handler: {(action, view, completion) in
                print("swipe action triggered!?")
                Task {
                    do{
                        let parameter = ["commentID": commentID, "action": "removeComment"]       // remove Comment
                        let returnDictionary = await APIs.shared.contactAPI(urlString: "APIURL.comments.php", parameter: parameter)
                    }
                }
                
                
                completion(true)
            })
            action.image = UIImage(systemName: "delete.left")
            action.backgroundColor = .systemRed
            return UISwipeActionsConfiguration(actions: [action])
        }

contactAPI:


func contactAPI(urlString: String, parameter: Dictionary<String,String>) async -> Dictionary<String, Any> {

        let encoder = JSONEncoder()
        encoder.outputFormatting = .prettyPrinted
        var jsonData = Data()
        do { jsonData = try encoder.encode(parameter) }
        catch let error { print("something went wrong here -.-: \(error)") }
        print(String(data: jsonData, encoding: .utf8)!) // for debugging
        
        let url = URL(string: urlString)
        var request = URLRequest(url: url!)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        
        let (data, _) = try! await URLSession.shared.upload(for: request, from: jsonData)
        
        //// for debugging
//        let dataString = String(data: data, encoding: .utf8)
//        print(dataString)
        
        let dictionary: [String: String] = try! JSONDecoder().decode([String: String].self, from: data)
//        print(dictionary)   // for debugging
//        var returnDic = Dictionary<String, Any>()
        
        return dictionary
    }

as you can see i have to call a network method inside that actionHandler, and xcode is complaining that the "trailingSwipeActionsConfigurationProvider": "Type of expression is ambiguous without more context"

if i remove that Task {} Block, everythings works as expected, so as i understood it there is a problem with that API call which of course is async, and can't find any documentation about that anywhere ..please help me out guys

CodePudding user response:

The compiler is complaining as it does not know how to interpret your code. The do block has to be followed by a catch block in swift.

documentation on error handling

The function you are trying to call is not throwing so no need for that do block at all. Just use:

Task {
    let parameter = ["commentID": commentID, "action": "removeComment"]       // remove Comment
    let returnDictionary = await APIs.shared.contactAPI(urlString: "APIURL.comments.php", parameter: parameter)
}

I have to admit I didn´t test this answer thoroughly. Sorry for that. It just seemed to be the most obvious error.

After disecting your code I found the issue:

Take a look at your functions signature

func contactAPI(urlString: String, parameter: Dictionary<String,String>) async -> Dictionary<String, Any> {

and the way you construct your argument

let commentID = Int32(commentIDString ?? 0)
    
let parameter = ["commentID": commentID, "action": "removeComment"]       // remove Comment
let returnDictionary = await APIs.shared.contactAPI(urlString: "APIURL.comments.php", parameter: parameter)

parameter is a [String:Any] here because commentID is of type Int and the next value is of type String. Anyway your function expects [String:String].

You need to fix this. It seems the best approach would be to create a custom struct for your parameters and encode that instead of this clumpsy dictionary approach.

Without knowing more about your code structure and needs for parameter I would recommend this struct:

struct Parameter: Codable{
    var commentID: Int
    var action: String
}


let commentIDString = self.dataSource.itemIdentifier(for: indexPath)?.commentID
let commentID = Int(commentIDString ?? "0") ?? 0

let action = UIContextualAction(style: .destructive, title: "", handler: {(action, view, completion) in
    print("swipe action triggered!?")
    
    Task {
            let parameter = Parameter(commentID: commentID, action: "removeComment")      // remove Comment
            let responseDict = await APIs.shared.contactAPI(urlString: "APIURL.comments.php", parameter: parameter)
    }


    completion(true)
})

The signature of your function would become:

func contactAPI(urlString: String, parameter: Parameter) async -> Dictionary<String, String> {

This should work this way. By the way, your String? to Int conversion was also flawed and would have thrown another error.

  • Related