无法从另一个视图控制器更改 UILabel.text,UILabel 得到 nil 值
Posted
技术标签:
【中文标题】无法从另一个视图控制器更改 UILabel.text,UILabel 得到 nil 值【英文标题】:Unable to Change UILabel.text from another View Controller, UILabel gets nil value 【发布时间】:2020-06-29 07:47:39 【问题描述】:我是一名新手程序员,正在尝试创建单视图天气应用程序。我的目标是编辑 dateLbl1 在 WeeklyWeatherViewController 中创建的 HomeViewController em>。
我的代码是这样写的:
let WeeklyWeatherView = WeeklyWeatherViewController()
...
WeeklyWeatherView.dateLbl1.text = nextDayShort[0].uppercased()
但是标签的值是“nil”。
致命错误:在隐式展开可选值时意外发现 nil
(nextDayShort 不为零,我将 UILabel 连接到 Storyboard)
在网上搜索我的问题并尝试将 ViewController 称为:
var swipePage: WeeklyWeatherViewController = UIStoryboard(name: "main", bundle: nil).instantiateViewControllerWithIdentifier("MyStoryboard")
我收到此错误:
线程 1:EXC_BAD_INSTRUCTION(代码=EXC_I386_INVOP,子代码=0x0)
我阅读了有关在视图控制器之间传递数据的信息,但根本无法在我的代码中使用它们。我该如何解决这个问题? 感谢您的帮助!
HomeViewController.swift
import UIKit
import Foundation
import CoreLocation
let DateView = DateViewController()
let WeatherView = WeatherViewController()
let WeeklyWeatherView = WeeklyWeatherViewController()
var currentHour : String?
var currentDay: String?
var nextDayShort = [String]()
var listCount = 0
class HomeViewController: UIViewController, CLLocationManagerDelegate
@IBOutlet var backgroudView: UIView!
@IBOutlet weak var daysView: UIView!
@IBOutlet weak var timeView: UIView!
@IBOutlet weak var splashImage: UIImageView!
@IBOutlet weak var weatherView: UIView!
@IBOutlet weak var middleView: UIView!
@IBOutlet weak var rightView: UIView!
@IBOutlet weak var leftView: UIView!
@IBOutlet weak var middleHourBGView: UIView!
var locationManager: CLLocationManager?
override func viewDidAppear(_ animated: Bool)
locationManager = CLLocationManager()
locationManager?.delegate = self
locationManager?.requestAlwaysAuthorization()
locationManager?.desiredAccuracy = kCLLocationAccuracyBest
locationManager?.startUpdatingLocation()
if CLLocationManager.locationServicesEnabled()
switch CLLocationManager.authorizationStatus()
case .restricted, .denied:
let alert = UIAlertController(title: "Locations servies are disabled!", message: "Please go to settings and allow location services or the application can't fetch weather data.", preferredStyle: .alert)
let settingsAction = UIAlertAction(title: "Settings", style: .default) (_) -> Void in
guard let settingsUrl = URL(string: UIApplication.openSettingsURLString) else
return
if UIApplication.shared.canOpenURL(settingsUrl)
UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!, options: [:], completionHandler: nil)
alert.addAction(settingsAction)
let cancelAction = UIAlertAction(title: "Cancel", style: .default, handler: nil)
alert.addAction(cancelAction)
self.present(alert, animated: true, completion: nil)
case .authorizedAlways, .authorizedWhenInUse:
print("Access")
@unknown default:
break
else
print("Location services are not enabled")
override func viewDidLoad()
super.viewDidLoad()
styleUI()
private func styleUI()
daysView.layer.cornerRadius = 10
daysView.layer.shadowOpacity = 0.5
daysView.layer.shadowOffset = .zero
daysView.layer.shadowRadius = 10
middleView.layer.cornerRadius = 25
middleHourBGView.layer.cornerRadius = 10
let now = Date()
let formatter = DateFormatter()
let hour = Calendar.current.component(.hour, from: Date())
formatter.timeZone = TimeZone.current
formatter.dateFormat = "MMMM dd,YYYY EEEE"
let dateString = formatter.string(from: now)
DateView.dateLbl?.text = dateString
currentHour = String(hour)
let formatter2 = DateFormatter()
for n in 1..<6
var dayComponent = DateComponents()
dayComponent.day = n
let theCalendar = Calendar.current
let nextDate = theCalendar.date(byAdding: dayComponent, to: Date())
formatter2.dateFormat = "EE"
let nextDaySh = formatter2.string(from: nextDate! as Date)
nextDayShort.append(nextDaySh)
DispatchQueue.main.async
WeeklyWeatherView.dateLbl1.text = nextDayShort[0].uppercased()
WeeklyWeatherView.dateLbl2.text = nextDayShort[1].uppercased()
WeeklyWeatherView.dateLbl3.text = nextDayShort[2].uppercased()
WeeklyWeatherView.dateLbl4.text = nextDayShort[3].uppercased()
WeeklyWeatherView.dateLbl5.text = nextDayShort[4].uppercased()
if (hour > 5 && hour < 21)
backgroudView.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
timeView.backgroundColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
daysView.layer.shadowColor = #colorLiteral(red: 0.3333333433, green: 0.3333333433, blue: 0.3333333433, alpha: 1)
else
backgroudView.backgroundColor = #colorLiteral(red: 0.0862745098, green: 0.09411764706, blue: 0.3058823529, alpha: 1)
timeView.backgroundColor = #colorLiteral(red: 0.0862745098, green: 0.09411764706, blue: 0.3058823529, alpha: 1)
DateView.cityLbl.textColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
DateView.dateLbl.textColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
DateView.tempLbl.textColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
daysView.layer.shadowColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
WeatherView.leftHourLbl.textColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
WeatherView.leftTempLbl.textColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
WeatherView.rightHourLbl.textColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
WeatherView.rightTempLbl.textColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
WeatherView.middleTempLbl.textColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
let location:CLLocationCoordinate2D = manager.location!.coordinate
weather.getWeather(lat: location.latitude, lon: location.longitude) weather in
DispatchQueue.main.async
DateView.cityLbl.text = weather.city.name
DateView.tempLbl.text = "\(Int(round(weather.list[0].main.temp)) - 273)°"
WeeklyWeatherView.tempLbl1.text = "\(Int(round(weather.list[1].main.temp)) - 273)°"
WeeklyWeatherView.tempLbl2.text = "\(Int(round(weather.list[2].main.temp)) - 273)°"
WeeklyWeatherView.tempLbl3.text = "\(Int(round(weather.list[3].main.temp)) - 273)°"
WeeklyWeatherView.tempLbl4.text = "\(Int(round(weather.list[4].main.temp)) - 273)°"
WeeklyWeatherView.tempLbl5.text = "\(Int(round(weather.list[5].main.temp)) - 273)°"
self.splashImage.isHidden = true
WeeklyWeatherViewController.swift
import UIKit
import Foundation
let storyBoardEdit = StoryboardEditor()
let weather = WeatherAPI()
class WeeklyWeatherViewController: UIView
@IBOutlet weak var dateLbl1: UILabel!
@IBOutlet weak var dateLbl2: UILabel!
@IBOutlet weak var dateLbl3: UILabel!
@IBOutlet weak var dateLbl4: UILabel!
@IBOutlet weak var dateLbl5: UILabel!
@IBOutlet weak var tempLbl1: UILabel!
@IBOutlet weak var tempLbl2: UILabel!
@IBOutlet weak var tempLbl3: UILabel!
@IBOutlet weak var tempLbl4: UILabel!
@IBOutlet weak var tempLbl5: UILabel!
@IBOutlet weak var weatherImg1: UIImageView!
@IBOutlet weak var weatherImg2: UIImageView!
@IBOutlet weak var weatherImg3: UIImageView!
@IBOutlet weak var weatherImg4: UIImageView!
@IBOutlet weak var weatherImg5: UIImageView!
func fillUI()
dateLbl1.text = nil
var dayId = [String]()
for x in 1..<6
dayId.append("03d")
let dayIdInt = Int(dayId[x-1])!
let imageIDName = storyBoardEdit.editWeatherIcons(dayIDInt: dayIdInt)
switch x
case 1:
DispatchQueue.main.async
self.weatherImg1.image = UIImage(named: imageIDName)
case 2:
DispatchQueue.main.async
self.weatherImg2.image = UIImage(named: imageIDName)
case 3:
DispatchQueue.main.async
self.weatherImg3.image = UIImage(named: imageIDName)
case 4:
DispatchQueue.main.async
self.weatherImg4.image = UIImage(named: imageIDName)
case 5:
DispatchQueue.main.async
self.weatherImg5.image = UIImage(named: imageIDName)
default:
break
【问题讨论】:
请分享您的完整代码... @jawadAli 已添加,谢谢。 不要将视图控制器声明为@IBOutlet @Stefan 感谢您的额外建议,我更新了我的代码并发布了。 如果它在 Storyboard 中,您确实应该使用第二种方法。但是,我认为问题在于视图未加载,因此插座也没有加载。你不是在展示视图控制器吗?那你为什么要设置它的标签值呢?你已经介绍了一个吗?如果是这样,您创建了一个全新的对象,而不是已经存在的对象。 【参考方案1】:做这些改变:
在 Storyboard(或 Xib)中,将weatherView
的类更新为 WeeklyWeatherViewController
并重置插座。你应该这样得到它:
@IBOutlet weak var weatherView: WeeklyWeatherViewController!
删除以下行:
let WeeklyWeatherView = WeeklyWeatherViewController()
在您的 styleUI()
方法中,将使用 WeeklyWeatherView
的行替换为:
DispatchQueue.main.async
weeklyWeatherView.dateLbl1.text = nextDayShort[0].uppercased()
weeklyWeatherView.dateLbl2.text = nextDayShort[1].uppercased()
weeklyWeatherView.dateLbl3.text = nextDayShort[2].uppercased()
weeklyWeatherView.dateLbl4.text = nextDayShort[3].uppercased()
weeklyWeatherView.dateLbl5.text = nextDayShort[4].uppercased()
在您的 locationManager() 函数中,将使用 WeeklyWeatherView
的行替换为:
weeklyWeatherView.tempLbl1.text = "\Int(round(weather.list[1].main.temp)) - 273)º"
weeklyWeatherView.tempLbl2.text = "\Int(round(weather.list[2].main.temp)) - 273)º"
weeklyWeatherView.tempLbl3.text = "\Int(round(weather.list[3].main.temp)) - 273)º"
weeklyWeatherView.tempLbl4.text = "\Int(round(weather.list[4].main.temp)) - 273)º"
weeklyWeatherView.tempLbl5.text = "\Int(round(weather.list[5].main.temp)) - 273)º"
看到我在这两种情况下都在使用新创建的插座,对吧?
【讨论】:
感谢您的回答。我像这样编辑了我的代码“let storyboard = UIStoryboard(name: "Main", bundle: nil) let WeeklyWeatherView = storyboard.instantiateInitialViewController()”但是得到了“'UIViewController 类型的值?'没有成员 'dateLbl1'"。 我用我的猜测更新了答案,你真的想在你的代码中做什么,你能检查一下吗? @EdwardMordrake 再次感谢您的出色回答。我按照这些步骤操作,但遇到了几个错误。对于“守卫让控制器....”行:“无法转换 'WeeklyWeatherViewController 类型的值?'到预期的参数类型“字符串”,预期的“,”分隔符,预期的表达式列表中的表达式”。对于“controller.didMove ...”行:“在 'guard' 条件之后预期 'else'” 对此感到抱歉...在guard let
语句中缺少右括号,已修复。
我非常感谢您的努力。我在您上次编辑后尝试了代码,但仍然出现一些错误。你可以从这里看到:i.imgur.com/JFsREGN.png【参考方案2】:
问题是你初始化WeeklyWeatherViewController
的方式
let WeeklyWeatherView = WeeklyWeatherViewController()
此视图有一个关联的 xib,您在其中创建了连接。现在,当您初始化 WeeklyWeatherViewController
类时,您的 xib 视图尚未初始化。
您需要在WeeklyWeatherViewController
的init
方法中加载nib 文件。
class WeeklyWeatherViewController: UIView
override init(frame: CGRect)
super.init(frame: frame)
let contentView = Bundle.main.loadNibNamed("your_nib", owner: self, options: nil)?.first as? UIView
addSubview(contentView!)
// set constraints for contentView.
convenience init()
let defaultFrame = //provide your default frame
self.init(frame: defaultFrame)
required init?(coder: NSCoder)
fatalError("init(coder:) has not been implemented")
所以问题是当您有一个关联的 xib 文件时,简而言之,当您从外部提供视图时,您需要初始化该外部视图并将其附加到您的类中。这样您的视图仍将保留在内存中,您可以访问所有已连接的IBOutlet
。
【讨论】:
以上是关于无法从另一个视图控制器更改 UILabel.text,UILabel 得到 nil 值的主要内容,如果未能解决你的问题,请参考以下文章