簡體   English   中英

單擊按鈕后,UILabel不會更新

[英]UILabel doesn't update after button click

后台Xcode版本8.2(8C38)
適用於iPhone 7 plus的ios 10.2-模擬器

我已經在Objective-C中完成了這項工作,現在正在嘗試使其迅速運行。 代碼會編譯並運行,但是單擊按鈕時,標簽不會更改。 如果標簽正在更新,我會將其發布在CR而不是此處。

開始時是面試帶回家的問題,但Objective-C部分讓我進行了現場面試。 我追求這一點以了解有關Swift的更多信息。 面試問題

/*
 * Create a static library or iOS Framework using Objective-C that performs the following 3 functions:
 * - Collects the GPS location (latitude and longitude) of the user at a point in time
 * - Collects the battery state and returns whether or not the device is plugged in and what percentage of life is left.
 * - Accesses any publicly available, free API to collect the data of your choice and returns it
 *        (this should be a network call)
 *
 * Build a simple application with 3 buttons and a label where text can be displayed.  Each button should call into the
 * three functions of the library described above and output the response to the label.  Your application should consist 
 * of two tabs, one written in Objective-C and one written in Swift.  Both tabs should call into the same Objective-C
 * library and perform the same function. 
 *
 * Only use Apple frameworks to complete this task. Fully comment your code explaining your logic and choices where multiple
 * choices are available. For example, Apple provides numerous ways to retrieve a network resource, document why you choose
 * the solution you did.
 */

這可能是一個重復的問題,但是我不確定我是否看過以下問題:

我不確定問題是否出在我進行的異步調用中,在按鈕本身的創建中還是在頂部的property / var聲明中。

import UIKit

class ViewController: UIViewController {
    var getGPSLongitudeAndLatitudeWithTimeStamp : UIButton?
    var getBatteryLevelAndState : UIButton?
    var getNextorkImplementation : UIButton?
    var displayButtonAction : UILabel?

    // The following variables are used in multiple functions. They are constant during the display of the super view
    // and control the size of the subviews
    var selfWidth : CGFloat = 0.0
    var buttonHeight : CGFloat = 0.0
    var viewElementWidth : CGFloat = 0.0
    var buttonYCenterOffset : CGFloat = 0.0       // The y center should be half the value of the height
    var buttonXCenter : CGFloat = 0.0             // Center the button title relative to the width of the button and the width of the super view
    var buttonXInit : CGFloat = 0.0
    var buttonVerticalSeparation : CGFloat = 0.0
    var startingVerticalLocation : CGFloat = 0.0
    var displayLabelHeight: CGFloat = 50.0

    func initFramingValuesOfMyDisplay() {
        selfWidth = self.view.bounds.size.width
        buttonHeight = 20.0               // This should be programmable in relative to self.view.bounds.size.height
        viewElementWidth = 0.8 * selfWidth;
        buttonYCenterOffset = buttonHeight / 2.0; // The y center should be half the value of the height
        buttonXCenter = selfWidth / 2.0;   // Center the button title relative to the width of the button and the width of the super view
        buttonXInit = 0.0;
        buttonVerticalSeparation = buttonHeight + buttonYCenterOffset;
        startingVerticalLocation = 430.0;  // 430 was chosen based on experimentation in the simulator
    }

    func setLabelWithGPSLatitudeAndLongitudeWithTimeStampData()
    {
        var actionString : String = "Testing Label Text"

        actionString = "GPS Button Action Failure: Data Model not created";

        DispatchQueue.global().async {
            self.displayButtonAction?.text = actionString
        }
    }

    func setLabelWithBatteryLevelAndState() {
        var actionString : String = "Get Battery Level and State";

        actionString = "Battery Button Action Failure: Data Model not created"

        DispatchQueue.global().async {
            self.displayButtonAction?.text = actionString
        }
    }

    func setLabelActionNetwork() {
        var actionString :String = "Fake Button set to American Express Stock Price";

        actionString = "Network Button Action Failure: Data Model not created";

        DispatchQueue.global().async {
            self.displayButtonAction?.text = actionString
        }
    }

    func makeAButton(yButtonStart : CGFloat, buttonTitle: String, underSubview: UIButton?) -> UIButton
    {
        let thisButton = UIButton.init(type: .system)
        thisButton.frame = CGRect(x: buttonXInit, y: yButtonStart, width: viewElementWidth, height: buttonHeight)
        thisButton.setTitle(buttonTitle, for:UIControlState.normal)

        thisButton.backgroundColor = UIColor.yellow
        thisButton.setTitleColor(UIColor.black, for: UIControlState.normal)
        if ((underSubview) == nil) {
            self.view.addSubview(thisButton)
        }
        else {
            self.view.insertSubview(thisButton, belowSubview:underSubview!)
        }

        return thisButton;
    }

    func makeALabel(yLabelStart : CGFloat, underSubview: UIButton?) -> UILabel
    {
        let thisLabel = UILabel.init()
        thisLabel.frame = CGRect(x: selfWidth * 0.1, y: yLabelStart, width: viewElementWidth, height: displayLabelHeight)

        thisLabel.font = thisLabel.font.withSize(12)
        thisLabel.lineBreakMode = .byWordWrapping;
        thisLabel.numberOfLines = 0;
        thisLabel.textAlignment = NSTextAlignment.center;
        thisLabel.textColor = UIColor.black;

        if ((underSubview) == nil) {
            self.view.addSubview(thisLabel)
        }
        else {
            self.view.insertSubview(thisLabel, belowSubview:underSubview!)
        }

        return thisLabel;
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.view.backgroundColor = UIColor.white
        initFramingValuesOfMyDisplay()
        addButtonAndLabels()
    }

    func addButtonAndLabels() -> Void {
        if (selfWidth < 1.0) {
            return;
        }
        var viewElementVerticalLocation: CGFloat = startingVerticalLocation;
        // var touchUpInside : UIControlEvents = touchUpInside;

        let getGPSLongitudeAndLatitudeWithTimeStamp : UIButton = makeAButton(yButtonStart: viewElementVerticalLocation, buttonTitle: "Get GPS Location with TimeStamp", underSubview: nil)
        getGPSLongitudeAndLatitudeWithTimeStamp.addTarget(self, action: #selector(setLabelWithGPSLatitudeAndLongitudeWithTimeStampData), for:  .touchUpInside)
        viewElementVerticalLocation += buttonVerticalSeparation

        let getBatteryLevelAndState : UIButton = makeAButton(yButtonStart: viewElementVerticalLocation, buttonTitle: "Get Battery Level and State", underSubview: getGPSLongitudeAndLatitudeWithTimeStamp)
        getBatteryLevelAndState.addTarget(self, action: #selector(setLabelWithBatteryLevelAndState), for:  .touchUpInside)
        viewElementVerticalLocation += buttonVerticalSeparation

        let getNextorkImplementation : UIButton = makeAButton(yButtonStart: viewElementVerticalLocation, buttonTitle: "Get Battery Level and State", underSubview: getBatteryLevelAndState)
        getNextorkImplementation.addTarget(self, action: #selector(setLabelWithBatteryLevelAndState), for:  .touchUpInside)
        viewElementVerticalLocation += buttonVerticalSeparation

        let displayButtonAction = makeALabel(yLabelStart: viewElementVerticalLocation, underSubview: getNextorkImplementation)
        displayButtonAction.text = "No Action Yet"
    }

    required init(coder aDecoder: NSCoder) {
        super.init(nibName: nil, bundle: nil)
        initFramingValuesOfMyDisplay()
    }
}

您的displayButtonAction實際上為nil。 請注意,在方法addButtonAndLabels()您將在此處創建標簽並僅在該方法的范圍內填充文本:

let displayButtonAction = makeALabel(yLabelStart: viewElementVerticalLocation, underSubview: getNextorkImplementation)

在您的makeALabel方法中,您正在將該標簽插入為視圖的子視圖,這就是為什么在運行應用程序時顯示該標簽的原因。 您無處將該標簽分配給displayButtonAction

總而言之,您將創建一個本地范圍UILabel ,填充它的占位符文本,將其作為視圖的子視圖插入,然后丟棄它,然后嘗試在按鈕按下nil填充displayButtonAction標簽的文本。

addButtonAndLabels() ,通過以下方式將實例化標簽分配給視圖控制器主范圍內的主標簽:

self.displayButtonAction = displayButtonAction

將幫助您朝正確的方向開始。

在這種情況下,使用調試器工具,斷點和po是您的朋友。

我注意到的主要事情是您試圖在后台隊列上設置標簽的文本。 除了主隊列之外,您永遠不要對UI進行更改,因此應將其更改為主隊列,如下所示:

DispatchQueue.main.async {
        self.displayButtonAction?.text = actionString
    }

您也應該在調試器中得到警告,告訴您這一點。

您還應該在該函數內拋出一個斷點,以驗證displayButtonAction不是nil,並且它具有實際在屏幕上且尺寸為非零的frame 充分利用這些調試器。

您無法在后台(異步)線程上更新UI元素。 您需要獲取線程才能執行此操作。

DispatchQueue.main.async(execute: {
    self.label.text = "some text"
})

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM