swift - 通过函数传递时不能修改对象数组?
问题描述
我创建了一个名为 Weather 的自定义类并声明了一个 Weather 对象数组。
import Foundation
class Weather {
var cityName:String
var temperature:Double
var temperatureMax:Double
var temperatureMin:Double
init(cityName: String, temperature: Double, temperatureMax: Double, temperatureMin: Double) {
self.cityName = cityName
self.temperature = temperature
self.temperatureMax = temperatureMax
self.temperatureMin = temperatureMin
}
}
import UIKit
import SwiftyJSON
class ViewController: UIViewController {
@IBOutlet weak var myLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
var weatherArrays = [Weather]()
findLocation(zipCode: "11210", weatherArrays: weatherArrays)
print(weatherArrays[0].cityName)
}
func findLocation(zipCode: String, weatherArrays: [Weather])
{
let zip = zipCode
let appID = "245360e32e91a426865d3ab8daab5bf3"
let urlString = "http://api.openweathermap.org/data/2.5/weather?zip=\(zip)&appid=\(appID)&units=imperial"
let request = URLRequest(url: URL(string: urlString)!)
URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
do
{
let json = try JSONSerialization.jsonObject(with: data!) as! NSDictionary
let main = json["main"] as! [String:Any]
let temp = main["temp"]! as! Double
let name = json["name"]! as! String
let tempMax = main["temp_max"]! as! Double
let tempMin = main["temp_min"]! as! Double
weatherArrays.append(Weather(cityName: name, temperature: temp, temperatureMax: tempMax, temperatureMin: tempMin))
}
catch
{
print("Error")
}
}.resume()
}
}
我将数组传递给一个函数,并将这些值附加到 weatherArrays 参数。但是,当我编译时出现错误,“不能对不可变值使用变异成员:'weatherArrays' 是一个 'let' 常量。”
Weather 类最初是一个结构,但我遇到了同样的错误,我阅读并发现结构值不能在函数中编辑,因为它是按值传递的。我将结构更改为一个类,但我仍然遇到同样的错误?当我将weatherArrays 声明为var 时,为什么它说“'weatherArrays' 是'let' 常量”?
解决方案
这是您的代码的更好方法
import UIKit
import SwiftyJSON
struct Weather {
let cityName:String
let temperature:Double
let temperatureMax:Double
let temperatureMin:Double
}
class ViewController: UIViewController {
@IBOutlet weak var myLabel: UILabel!
var array = [Weather]()
let appID = "245360e32e91a426865d3ab8daab5bf3"
override func viewDidLoad() {
super.viewDidLoad()
findLocation(zipCode: "11210"){ array in
guard let array = array else {
print("Error")
return
}
print(array.first?.cityName ?? "no city name found")
}
}
func buildUrl(queryItems: [URLQueryItem]) -> URL?{
var components = URLComponents()
components.scheme = "http"
components.host = "api.openweathermap.org"
components.path = "/data/2.5/weather"
components.queryItems = queryItems
return components.url
}
func findLocation(zipCode: String, completionHandler: @escaping (_ array: [Weather]?) -> ()){
guard let url = buildUrl(queryItems: [URLQueryItem(name: "zip", value: zipCode), URLQueryItem(name: "appID", value: appID), URLQueryItem(name: "units", value: "imperial")]) else {
print("Error in building url")
return
}
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in
guard let data = data else {
print(error?.localizedDescription ?? "")
completionHandler(nil)
return
}
do{
var array = [Weather]()
let json = try JSON(data: data)
if json["cod"].intValue == 200{
let main = json["main"]
let temp = main["temp"].doubleValue
let name = json["name"].stringValue
let tempMax = main["temp_max"].doubleValue
let tempMin = main["temp_min"].doubleValue
array.append(Weather(cityName: name, temperature: temp, temperatureMax: tempMax, temperatureMin: tempMin))
completionHandler(array)
}else{
completionHandler(nil)
}
} catch let error{
print(error)
}
}.resume()
}
}
模型用struct,不用写init方法
当您知道数据不会被更改时,使用 let 而不是 var
不要使用 NSDictionary。
您在调用函数后立即编写了 print 语句,因为只有在调用服务器完成后才会填充数组。所以我使用了完成处理程序
我看到您已经安装了 SwiftyJSON,但您实际上并没有使用它的好处。看解析部分。
关于你得到的错误是因为 Swift 是按值传递的,即当你传递数组对象时,你实际上传递的是它的副本而不是实际的数组。如果你想修改同一个数组,你需要我们inout。可以找到一个很棒的教程
编辑:正如@rmaddy 所建议的,通过返回一个新数组来使代码更安全。请参阅他的评论以获取更多信息。
推荐阅读
- vb.net - 如何将 MouseHover 和 MouseLeave 应用于两个控件以充当一个控件?
- php - 列出的项目未对齐并连续跳过 2 个项目空间
- react-native - 带有“./environment/validate.fx”的 Jest 中出现意外的字符串错误;
- java - 日期递增的 Hive UDF
- python - 获取满足条件的行的最大值
- swift - Swift Combine:如何从发布者列表中创建单个发布者?
- javascript - React hooks 陈旧状态
- python - 使用turtle.onclick() 改变变量
- css - 引导行映射宽度最大化
- .net - 在 Azure DevOps 中为 .NET Framework 4.7.x 构建 Docker 容器