ios - 我正在尝试循环遍历字符串数组并触发 api 调用以重新加载 Collection View

标签 ios swift for-loop asynchronous alamofire

import UIKit
import GooglePlaces
import Alamofire
import CoreData

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return listData?.count ?? 0
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CityCollectionViewCell

    let city = listData![indexPath.row] as? NSDictionary
    let name = city?.object(forKey: "name") as? String
    let main = city?.object(forKey: "main") as! NSDictionary
    let temp = main.object(forKey: "temp") as? Double
    let date1 = city?.object(forKey: "dt")

    let date = Date(timeIntervalSince1970: date1 as! TimeInterval)
    let dateFormatter = DateFormatter()
    dateFormatter.timeZone = TimeZone(abbreviation: "GMT") //Set timezone that you want
    dateFormatter.locale = NSLocale.current
    dateFormatter.dateFormat = "yyyy-MM-dd HH:mm" //Specify your format that you want
    let strDate = dateFormatter.string(from: date)

    cell.cityLabel.text = name!
    cell.lastUpdatedLabel.text = strDate
    cell.tempLabel.text = "\(temp!)"

    return cell
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

    cv.deselectItem(at: indexPath, animated: true)

    let row = indexPath.row;
    let selectedCity = list![row];

    userDefaults?.set(selectedCity, forKey: "citySelection");
    self.performSegue(withIdentifier: "selectCity", sender: self);
}


@IBOutlet weak var cv: UICollectionView!

var userDefaults:UserDefaults?;

var list:NSMutableArray?
var listData:NSMutableArray?
let group = DispatchGroup()

override func viewDidLoad() {
    super.viewDidLoad()

    userDefaults = UserDefaults.standard;

}


@IBAction func addCity(_ sender: Any) {
    let autocompleteController = GMSAutocompleteViewController()
    autocompleteController.delegate = self
    let addressFilter = GMSAutocompleteFilter()
    addressFilter.type = .city
    autocompleteController.autocompleteFilter = addressFilter
    present(autocompleteController, animated: true, completion: nil)
}


override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    updateValues()

}
func updateValues()  {
    let list = getSearchHistory()
    print(list)
        let count = list.count
    if count > 0
     {
        for item in list {
            group.enter()
                getData(name: item as! String)
        }
        group.notify(queue: .main, execute: {
            self.cv.reloadData()
        })
    }
}

func getData(name: String)  {
    let modified = name.replacingOccurrences(of: " ", with: "+")
    let url = "http://api.openweathermap.org/data/2.5/weather?q=\(modified)&APPID=-------"

    Alamofire.request(url, method: HTTPMethod.get).responseJSON(completionHandler: {
        (response) -> Void in

        let city = response.result.value as! NSDictionary;
        self.listData?.add(city)
        print(self.listData)
        self.group.leave()
    })
}

func addToSearchHistory(locationName:String) {

    let delegate = UIApplication.shared.delegate as! AppDelegate
    let managedContext = delegate.persistentContainer.viewContext;
    let entity = NSEntityDescription.insertNewObject(forEntityName: "SavedPlaces", into: managedContext)
    entity.setValue(locationName, forKey: "name")

    do {
        try managedContext.save();
    }
    catch {
        print("Core data error");
    }
}

func getSearchHistory() -> NSMutableArray {
    let returnData = NSMutableArray()
    let delegate = UIApplication.shared.delegate as! AppDelegate
    let managedContext = delegate.persistentContainer.viewContext;

    do {
        let req = NSFetchRequest<NSFetchRequestResult>(entityName: "SavedPlaces");

        let data = try managedContext.fetch(req) as! [NSManagedObject];

        for item in data {
            let name = item.value(forKey: "name") as? String;
            returnData.add(name!);
        }
    }
    catch {
        print("Core data error");
    }

    return returnData;
}

}

 extension ViewController: GMSAutocompleteViewControllerDelegate {

// Handle the user's selection.
func viewController(_ viewController: GMSAutocompleteViewController, didAutocompleteWith place: GMSPlace) {
    self.addToSearchHistory(locationName: place.name)
    dismiss(animated: true, completion: nil)
}

func viewController(_ viewController: GMSAutocompleteViewController, didFailAutocompleteWithError error: Error) {
    // TODO: handle the error.
    print("Error: ", error.localizedDescription)
}

// User canceled the operation.
func wasCancelled(_ viewController: GMSAutocompleteViewController) {
    dismiss(animated: true, completion: nil)
}

// Turn the network activity indicator on and off again.
func didRequestAutocompletePredictions(_ viewController: GMSAutocompleteViewController) {
    UIApplication.shared.isNetworkActivityIndicatorVisible = true
}

func didUpdateAutocompletePredictions(_ viewController: GMSAutocompleteViewController) {
    UIApplication.shared.isNetworkActivityIndicatorVisible = false
}

 }

我尝试使用 core Data 从存储的数据中加载值,然后循环遍历字符串并调用 api,然后将其添加到一个新数组中,从中填充 Collection View 。

问题:我已正确填充所有值(城市名称)列表,但在调用 api 并调用“UpdateUI”函数后,我只得到一个单元格。 gif file

最佳答案

请求尚未完成,这是一个异步任务,等待我将为您处理代码,这样每当有新响应时,tableView 就会重新加载以反射(reflect)该情况

   func updateValues()  {
    let list = getSearchHistory()

    if !list.isEmpty
     {
        for item in list {
                getData(name: item as! String)
        }

    }
}

func getData(name: String)  {
    let modified = name.replacingOccurrences(of: " ", with: "+")
    let rr = NSMutableArray()
    let url = "http://api.openweathermap.org/data/2.5/weather?q=\(modified)&APPID=------------------"

    Alamofire.request(url, method: HTTPMethod.get).responseJSON(completionHandler: {
        (response) -> Void in

        let city = response.result.value as! NSDictionary;

        rr.add(city)
       self.listData.append(rr)

       DispatchQueue.main.async
        {
               self.cv.reloadData()
         }           



    })
}

另请注意一个非常重要的步骤,以响应您覆盖当前数组而不是附加到它

  self.listData = rr

应该是

 self.listData.append(rr)

无论是否发生加载,这都会导致永久显示一项

enter image description here

另外不要忘记在 viewDidLoad 中初始化 listData

  listData = NSMutableArray()

尝试像这样解析 api

-(void)getDataforCity:(NSString*)cityName
{

  NSURL*url = [NSURL URLWithString:[NSString stringWithFormat:@"%@?APPID=%@&q=%@",openWeatherMapBaseURL,openWeatherMapAPIKey,cityName]];

 [NSURLSession.sharedSession dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

    if(error == nil)
    {

        NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];

       NSDictionary*main = json[@"main"];

        NSString*humidity = main[@"humidity"];

        NSString*pressure = main[@"pressure"];

        NSString*temp = main[@"temp"];

        NSString*tempMax = main[@"temp_max"];

        NSString*tempMin = main[@"temp_min"];

        NSArray*weatherArr = json[@"weather"];

        NSDictionary*weather = weatherArr[0];

        NSString*description = weather[@"description"];

        NSDictionary*wind = json[@"wind"];

        NSString*deg = wind[@"deg"];

        NSString*speed = wind[@"speed"];

        NSLog(@"humidity %@ : ",humidity);
        NSLog(@"pressure %@ : ",pressure);
        NSLog(@"temp %@ : ",temp);
        NSLog(@"tempMax %@ : ",tempMax);
        NSLog(@"tempMin %@ : ",tempMin);
        NSLog(@"description %@ : ",description);
        NSLog(@"deg %@ : ",deg);
        NSLog(@"speed %@ : ",speed);

       NSLog(@"dasdasddasdataioioio : %@",json);
    }
    else
    {
        NSLog(@"dasdasddasdata : %@",error);
    }


}].resume;

}

关于ios - 我正在尝试循环遍历字符串数组并触发 api 调用以重新加载 Collection View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48174549/

相关文章:

ios - 实例和初始化的区别

ios - 使用 NSManagedObjectContextWillSaveNotification 识别已更改对象的旧值和新值

php - 在 swift 中使用 HTTP POST 发送文本和图像

objective-c - 为什么这段代码会泄漏内存?

c++ - for循环只循环3次

ios - 如何隐藏具有纵横比自动布局约束的 UIImageView?

ios - 改变 Objective-C 中的约束

swift - 如何使用 AVPlayer (macOS) 循环播放视频?

ios - 更改 SFSafariViewController 的颜色?

javascript - 数组仅在 for 循环的第一次迭代时更新