无法从另一个视图控制器更改 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 【问题描述】:

我是一名新手程序员,正在尝试创建单视图天气应用程序。我的目标是编辑 dateLbl1WeeklyWeatherViewController 中创建的 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 视图尚未初始化。

您需要在WeeklyWeatherViewControllerinit 方法中加载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 值的主要内容,如果未能解决你的问题,请参考以下文章

按下后退按钮后,从另一个视图控制器更改按钮

快速从另一个视图控制器更改 webview 的 url

从另一个视图控制器单击 uitableviewcell 后,swift 3 更改 uitableviewcell?

如何从另一个视图控制器更改标签的文本并使用核心数据保存

无法从另一个视图控制器获取表视图数据

无法从另一个 tableview 加载另一个 tableView