无法以编程方式从API拉动更改UIImageView的图像

时间:2019-06-13 04:44:59

标签: swift uiimageview uiimage

我牛仔为趣味性编写了一个小天气应用程序。据我所知,UI看起来很不完美,但我正在重做以符合具有可伸缩性的行业标准代码。无论如何,在OG代码中,我的ViewController的UIImageView扩展中具有下载功能,实际上,它实际上是在线程中下载图像,然后基于此以编程方式更改UIImageView。

现在,相反,我具有该下载功能,就像在Service类中的常规功能一样,我在ViewModel类中调用它来执行相同的操作,然后将URL存储在我的模型类和viewmodel类之一中。

一切正常。我在更改图像之前和更改之后打印出图像,我可以说它已经更改,而且也不为零,所以我知道它可以工作。我现在已经使用相同的下载功能了很久了,唯一的区别是我现在将其作为常规功能而不是扩展功能来使用。

反正下面是代码:

import UIKit
import CoreLocation

class ViewController: UIViewController {

    //UI variables
    @IBOutlet var weatherImage: UIImageView!
    @IBOutlet var test: UITextField!

    //Location Object
    let locationManager = CLLocationManager()


    override func viewDidLoad() {
        super.viewDidLoad()
        locationManager.requestWhenInUseAuthorization()
        //        locationManager.requestLocation()
        if (CLLocationManager.locationServicesEnabled()){
            locationManager.delegate = self
            locationManager.desiredAccuracy = kCLLocationAccuracyBest
            locationManager.startUpdatingLocation()
        }
    }

    func populateView(currentLocationVM : LocationWeatherVM){
        //this prints the default image prior to messing around with it
        print(weatherImage.image)
        print(weatherImage.image)
        //this is to test to see if other UI components are able to be dynamically changed
        self.test.text = currentLocationVM.city
        //self.weatherImage = currentLocationVM.weatherImage
        //this was to test if I changed these properties if it could help
        let test = currentLocationVM.weatherImage
        test.clipsToBounds = true
        test.autoresizesSubviews = true
        self.weatherImage = test
        print("")
        print("")
        print("")
        //these match as the new image
        print(weatherImage.image)
        print(weatherImage.image)
        print("")
        print("")
        print("")
        let temp = UIImageView()
        print(temp.image) //this is empty
    }

}

/**
 CLLocationManagerDelegate extension for the Vew Controller class

 - important: didFailWithError and didUpdateLocations are for testing purposes. didChangeAuthorizationStatus is used for requesting process. didUpdateLocations is ALSO used for starting the functionality's chain of events once the user location has been found

 In later updates, this can return a message to the user if there isn't enough network power to get a search (say...within a few seconds?)
 */
extension ViewController : CLLocationManagerDelegate{
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if locations.first != nil {
            print("location: (location)")
            let currentLongitude = manager.location!.coordinate.longitude
            let currentLatitude = manager.location!.coordinate.latitude
            //service to get current location info - weather info and store it as viewmodel to then displays upon app launch
            //essentially do the fetchcourses thing but one for fetchLocation then one for fetchWeather
            //map that to a viewModel then call the populateView func
            let service = Service()
            let currentLocationVM = service.fetchCurrentViewModelInfo(currentLongitude: currentLongitude, currentLatitude: currentLatitude)
            print(currentLocationVM)
            populateView(currentLocationVM: currentLocationVM)

            //load old UI Searches
            manager.delegate = nil

        }
    }
}

我的服务班级:

import Foundation
import CoreLocation
import GooglePlaces
import GoogleMaps
import UIKit

class Service: NSObject {
    static let shared = Service()
    let googleAPIKey = "i'mnottellingumyapikeyhaha"
    let commaSpace = ","

    func fetchCurrentViewModelInfo(currentLongitude: CLLocationDegrees, currentLatitude: CLLocationDegrees) -> LocationWeatherVM{
        let locationInfo = getLocationInfoFromPlaceID(placeID: getCurrentPlaceID(currentLongitude: currentLongitude, currentLatitude: currentLatitude))
        print("or here")
        let weatherInfo = fetchWeather(locationInfo: locationInfo)
        return LocationWeatherVM(locationInfo: locationInfo, weatherInfo: weatherInfo)
    }

    func getCurrentPlaceID(currentLongitude: CLLocationDegrees, currentLatitude: CLLocationDegrees) -> String {
        let currLat = String(currentLatitude)
        let currLong = String(currentLongitude)
        var placeID: String!

        let semaphore = DispatchSemaphore(value: 0)
        print("https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=\(currLat),\(currLong)&radius=1&key=\(googleAPIKey)")
        let urlRequest = URLRequest(url: URL(string: "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=\(currLat),\(currLong)&radius=1&key=\(googleAPIKey)")!)
        let task = URLSession.shared.dataTask(with: urlRequest){(data, response, err) in
            if err == nil{
                guard let data = data else { return }
                do{
                    let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! [String: AnyObject]
                    guard let results = json["results"] as? NSArray else { return }
                    guard let firstResult = results[0] as? NSDictionary else { return }
                    guard let place_id = firstResult["place_id"] as? String else { return }
                    placeID = place_id
                    semaphore.signal()
                }catch let jsonError{
                    print(jsonError.localizedDescription)
                }
            }
        }
        task.resume()
        semaphore.wait()
        return placeID
    }

    func getLocationInfoFromPlaceID(placeID: String) -> LocationInfo{
        var cityName: String!
        var stateName: String!
        var countryName: String!

        let semaphore = DispatchSemaphore(value: 0)
        print("https://maps.googleapis.com/maps/api/place/details/json?placeid=\(placeID)&fields=address_components&key=\(googleAPIKey)")
        let urlRequest = URLRequest(url: URL(string: "https://maps.googleapis.com/maps/api/place/details/json?placeid=\(placeID)&fields=address_components&key=\(googleAPIKey)")!)
        let task = URLSession.shared.dataTask(with: urlRequest){(data, response, err) in
            if err == nil{
                guard let data = data else { return }
                do{
                    print("hold on")
                    let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! [String: AnyObject]
                    guard let result = json["result"] as? NSDictionary else { return }
                    guard let address_components = result["address_components"] as? NSArray else { return }
                    for n in 0...address_components.count-1 {
                        let temp = address_components[n] as? NSDictionary
                        let temp1 = temp?["types"] as? NSArray
                        let temp2 = temp1?[0] as? NSString
                        if temp2 == "locality"{
                            cityName = temp!["short_name"] as? String
                        }
                        if temp2 == "administrative_area_level_1"{
                            stateName = temp!["short_name"] as? String
                        }
                        if temp2 == "country"{
                            countryName = temp!["short_name"] as? String
                        }
                    }
                    semaphore.signal()
                } catch let jsonError{
                    print(jsonError.localizedDescription)
                }
            }
        }
        task.resume()
        semaphore.wait()
        return LocationInfo(city: cityName, state: stateName, country: countryName)
    }

    func fetchWeather(locationInfo : LocationInfo) -> WeatherInfo{
        var temperature: Double!
        var weatherImageURL: String!
        var precipitation: Double!
        var time: Array<Any>!

        let cityTemp = locationInfo.city.replacingOccurrences(of: " ", with: "%20")
        let stateTemp = locationInfo.state.replacingOccurrences(of: " ", with: "")
        let countryTemp = locationInfo.country.replacingOccurrences(of: " ", with: "")

        let semaphore = DispatchSemaphore(value: 0)
        print("http://api.apixu.com/v1/current.json?key=bd662599761d4279a0b30426192405&q=\(cityTemp)\(commaSpace)\(stateTemp)\(commaSpace)\(countryTemp)")
        let urlRequest = URLRequest(url: URL(string: "http://api.apixu.com/v1/current.json?key=bd662599761d4279a0b30426192405&q=\(cityTemp)\(commaSpace)\(stateTemp)\(commaSpace)\(countryTemp)")!)
        let task = URLSession.shared.dataTask(with: urlRequest){(data, response, error) in
            if error == nil{
                do{
                    let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String: AnyObject]
                    guard let current = json["current"] as? [String: AnyObject] else { return }
                    guard let temp = current["temp_f"] as? Double else { return }
                    temperature = temp
                    guard let condition = current["condition"] as? [String: AnyObject] else { return }
                    let icon = condition["icon"] as! String
                    weatherImageURL = "http:\(icon)"
                    guard let precipIn = current["precip_in"] as? Double else { return }
                    precipitation = precipIn
                    guard let location = json["location"] as? [String: AnyObject] else { return }
                    let timeStamp = location["localtime"]
                    let sepTimeStamp = timeStamp?.components(separatedBy: " ")
                    let tempTime = sepTimeStamp?[1]
                    time = Array(tempTime!)
                    semaphore.signal()
                } catch let jsonError{
                    print(jsonError.localizedDescription)
                }
            }
        }
        task.resume()
        semaphore.wait()
        let weatherImage = UIImageView(image: downloadImage(weatherImageURL : weatherImageURL))
        return WeatherInfo(precipitation: precipitation, temperature: temperature, weatherImage: weatherImage, time: time)
    }

    func downloadImage(weatherImageURL : String) -> UIImage{
        var weatherImage = UIImage()

        let semaphore = DispatchSemaphore(value: 0)
        let url = URL(string: weatherImageURL)!
        let task = URLSession.shared.dataTask(with: url){(data, response, err) in
            if err == nil{
                //guard let data = data else { return }
                print(data)
                print(weatherImageURL)
                weatherImage = UIImage(data: data!)!
                semaphore.signal()
            }
        }
        task.resume()
        semaphore.wait()
        return weatherImage
    }
}

我的LocationWeatherVM类:

import Foundation
import UIKit

struct LocationWeatherVM{

    //Location Variables
    let city: String
    let state: String
    let country: String

    //Weather Variables
    let isRainy: Bool
    let temperature: Double
    let weatherImage: UIImageView
    //let greeting: String
    //let greetingMsg: String

    init (locationInfo: LocationInfo, weatherInfo: WeatherInfo){
        self.city = locationInfo.city
        self.state = locationInfo.state
        self.country = locationInfo.country

        self.temperature = weatherInfo.temperature
        self.weatherImage = weatherInfo.weatherImage
        if weatherInfo.precipitation > 0{
            self.isRainy = true
        }else{
            self.isRainy = false
        }
    }
}

当然,现在我还没有包括所有内容,只是现在才开始重新构建所有内容。我要使用MVVM,因此如果您认为我的结构不正确,也可以对此发表评论。

现在,我只是想显示当前的用户位置和天气信息,这是OG应用在启动时正在执行的操作,而不是加载旧的搜索位置(如果有的话),但这完全是另外一回事了。谢谢大家:D

0 个答案:

没有答案