简体   繁体   English

快速在异步调用上使用参数

[英]Using parameters on async call in swift

I'm having an async call with a completionhandler that fetches data for me through a query. 我正在与完成处理程序进行异步调用,该处理程序通过查询为我获取数据。 These queries can vary based upon the users action. 这些查询可以根据用户操作而有所不同。

My data call looks like this; 我的数据通话看起来像这样;

class DataManager {
    func requestVideoData(query: QueryOn<VideoModel>, completion: @escaping (([VideoModel]?, UInt?, Error?) -> Void)) {
        client.fetchMappedEntries(matching: query) { (result: Result<MappedArrayResponse<FRVideoModel>>) in
            completion(videos, arrayLenght, nil)
        }
    }
}

My ViewController looks like this; 我的ViewController看起来像这样;

DataManager().requestVideoData(query: /*One of the queries below*/) { videos, arrayLength, error in
    //Use the data fetched based on the query that has been entered
}

My queries look like this; 我的查询看起来像这样;

let latestVideosQuery = QueryOn<FRVideoModel>().limit(to: 50)
try! latestVideosQuery.order(by: Ordering(sys: .createdAt, inReverse: true))

And this; 和这个;

let countryQuery = QueryOn<FRVideoModel>()
        .where(valueAtKeyPath: "fields.country.sys.contentType.sys.id", .equals("country"))
        .where(valueAtKeyPath: "fields.country.fields.countryTitle", .includes(["France"]))
        .limit(to: 50)

But I'm not completely sure how I would implement these queries the right way so they correspond with the MVC model. 但是我不确定如何正确地实现这些查询,以使其与MVC模型相对应。

I was thinking about a switch statement in the DataManager class, and pass a value into the query parameter on my ViewController that would result in the right call on fetchMappedEntries(). 我正在考虑在DataManager类中使用switch语句,并将一个值传递到ViewController的查询参数中,这将导致对fetchMappedEntries()的正确调用。 The only problem with this is that I still need to execute the correct function according to my query in my VC, so I would need a switch statement over there as well. 唯一的问题是,我仍然需要根据我的VC中的查询执行正确的功能,因此我也需要在那儿使用switch语句。

Or do I need to include all my queries inside my ViewController? 还是我需要将所有查询都包含在ViewController中? This is something I think is incorrect because it seems something that should be in my model. 我认为这是不正确的,因为它似乎应该在我的模型中。

This is somewhat subjective. 这有点主观。 I think you are right to want to put the construction of the queries in your DataManager and not in your view controller. 我认为将查询的结构放在DataManager而不是在视图控制器中是正确的。

One approach is to dumb down the request interface, so that the view controller only needs to pass a simple request, say: 一种方法是简化请求接口,以便视图控制器仅需要传递一个简单的请求,例如:

struct QueryParams {
    let limit: Int?
    let country: String?
}

You would then need to change your DataManager query function to take this instead: 然后,您需要更改DataManager查询函数以采用此方法:

func requestVideoData(query: QueryParams, completion: @escaping (([VideoModel]?, UInt?, Error?) -> Void))

Again, this is subjective, so you have to determine the tradeoffs. 同样,这是主观的,因此您必须确定权衡。 Dumbing down the interface limits the flexibility of it, but it also simplifies what the view controller has to know. 钝化接口限制了它的灵活性,但是它也简化了视图控制器必须知道的内容。

In the end I went with a slightly modified networking layer and a router where the queries are stored in a public enum, which I can then use in my functions inside my ViewController. 最后,我使用了稍微修改的网络层和一个路由器,将查询存储在一个公共枚举中,然后可以在ViewController中的函数中使用它们。 Looks something like this; 看起来像这样;

public enum Api {
    case latestVideos(limit: UInt)
    case countryVideos(countries: [String], limit: UInt)
}

extension Api:Query {
    var query: QueryOn<VideoModel> {
        switch self {
        case .latestVideos(let limit):
            let latestVideosQuery = QueryOn<VideoModel>().limit(to: limit)
            try! latestVideosQuery.order(by: Ordering(sys: .createdAt, inReverse: true))
            return latestVideosQuery
        case .countryVideos(let countries, let limit):
            let countryQuery = QueryOn<VideoModel>()
                .where(valueAtKeyPath: "fields.country.sys.contentType.sys.id", .equals("country"))
                .where(valueAtKeyPath: "fields.country.fields.countryTitle", .includes(countries))
                .limit(to: limit)
            return countryQuery
        }
    }
}

And the NetworkManager struct to fetch the data; 然后使用NetworkManager结构来获取数据;

struct NetworkManager {
    private let router = Router<Api>()

    func fetchLatestVideos(limit: UInt, completion: @escaping(_ videos: [VideoModel]?, _ arrayLength: UInt?,_ error: Error?) -> Void) {
        router.requestVideoData(.latestVideos(limit: limit)) { (videos, arrayLength, error) in
            if error != nil {
                completion(nil, nil, error)
            } else {
                completion(videos, arrayLength, nil)
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM