我正在使用合并使用我的API的响应更新我的collectionView,以提供真实的信息。我的API返回工作正常的NSArray,但由于SearchAPI类中的一些奇怪原因,我可以接收响应并在控制台中打印出来**打印(“我们的数组“,searchArray)**但无法接收到我的UIViewController并相应地更新我的collectionView。**print(“value“,value)**Value始终为空
import Foundation
import Combine
class SearchAPI {
static let shared = SearchAPI()
func fetchData(url: String, category: String, queryString: String) -> Future<NSArray, Error>{
var searchArray: NSArray = []
let urlString = url
print("url come ", urlString)
guard let url = URL(string: urlString) else {
fatalError()
}
var request = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Accept")
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request) { [weak self] data, response, error in
guard let data = data, error == nil else {
return
}
do{
let json = try? JSONSerialization.jsonObject(with: data, options: []) as? NSArray
if let responseJson = json {
searchArray = responseJson
print("Our array", searchArray)
}
}
}
task.resume()
return Future { promixe in
DispatchQueue.main.async {
promixe(.success(searchArray))
}
}
}
}
//In my UIViewController
var observers: [AnyCancellable] = []
let action = PassthroughSubject<NSArray, Never>()
var category = "tv"
var queryString = ""
private var models: NSArray = []
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if isMovieSelected {
btnMoviesBottomBorder.backgroundColor = .secondaryPink
btnAlbumsBottomBorder.backgroundColor = .systemGray
btnAlbumsBottomBorder.backgroundColor = .systemGray
}
txtSearch.searchTextField.addTarget(self, action: #selector(searchItem), for: .editingChanged)
}
@objc func searchItem(){
moviesView.alpha = 0
albumsView.alpha = 0
booksView.alpha = 0
lblSrchResults.alpha = 1
queryString = txtSearch.text!.replacingOccurrences(of: " ", with: "%20")
print("who is calling ", queryString)
let url = "https://endpoint?category=\(category)&query=\(queryString)"
SearchAPI.shared.fetchData(url: url, category: category, queryString: queryString)
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { completion in
switch completion {
case .finished:
print("finished")
case .failure(let error):
print(error)
}
}, receiveValue: { [weak self] value in
print("value ", value)
self?.models = value
self?.searchCollectionView!.reloadData()
}).store(in: &observers)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
print("Fetched ", models.count)
return models.count
}
1条答案
按热度按时间vhipe2zx1#
在
fetchData
函数中,创建一个dataTask
来运行URL请求,在稍后的某个时刻,dataTask将完成并返回一个数组。然后创建一个
Future
,并发送一些代码在主队列上运行,这些代码中没有任何内容可以让它等待dataTask
完成。Future
中的代码将“立即”运行,并在为searchArray
赋值之前完成。你需要修改你的
Future
,使它只在dataTask
完成后才解析(只完成)。稍微调整一下你的代码,它看起来像这样:我把它输入了一个操场,但我没有运行它,所以可能需要额外的更改。
现在所有的动作都发生在未来,一旦你在未来块中,你就应该调用它的resolution函数(在你的代码中叫做
promixe
)来处理所有成功或失败的情况。我修改了代码,以便仅在数据任务完成(成功或不成功)时调用
promixe
。对于您的代码,您可能还应该:
Futures
块的每个路径上调用proximate
一次。特别是,您需要捕获JSONSerialization
可能给您带来的错误,并调用promixe
报告错误。否则,如果数据从服务器返回,但无法解析,您的未来可能无法完成。JSONSerialization
,这样您将使用[SomeType]
而不是NSArray
。使用类型系统以减少错误的可能性。txtSearch.text!.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
代替queryString = txtSearch.text!.replacingOccurrences(of: " ", with: "%20")
。如果用户输入一些意外的内容,它将涵盖更多的情况。