UILabel не обновляется после нажатия кнопки

Фон Xcode Version 8.2 (8C38) ios 10.2 для iPhone 7 плюс - Симулятор

Я использую Xcode в течение 2 недель, получил эту работу в объективе-c, и теперь я пытаюсь заставить ее работать быстро. Код компилируется и запускается, но при нажатии на кнопки метка не изменяется. Если метка обновлялась, я бы разместил ее на CR, а не здесь.

Пожалуйста, извините многословие вопроса.

Это началось с того, что собеседование взяло на себя главный вопрос, но часть "цель-с" дала мне интервью на месте. Я преследую это, чтобы узнать больше о быстром. Интервью

/*
 * 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.
 *
 * Please send me the full SINGLE Xcode project.
 */

Это может быть дублирующий вопрос, но я не уверен, что посмотрел на следующие вопросы:

Swift Update Label (с содержимым HTML) занимает 1 минуту

Параллельные и последовательные очереди в GCD

Как создать очередь отправки в Swift 3 Swift 3 предупреждение для отправки async

Я не уверен, что проблема заключается в вызове async, который я создаю, при создании самой кнопки или объявления свойств /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"
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    required init(coder aDecoder: NSCoder) {
        super.init(nibName: nil, bundle: nil)
        initFramingValuesOfMyDisplay()
    }

}
+1
источник поделиться
3 ответа

Ваш displayButtonAction фактически равен нулю. Обратите внимание, что в методе addButtonAndLabels() вы создаете метку и addButtonAndLabels() текст только в рамках этого метода здесь:

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

В вашем методе makeALabel вы вставляете эту метку в качестве подсмотра вашего представления, поэтому она появляется при запуске приложения. Нигде вы не назначаете эту метку displayButtonAction.

Таким образом, вы создаете локальную область UILabel, UILabel ее текстом-заполнителем, вставляя ее как подвид вашего представления, а затем отбрасывая его, а затем пытаясь заполнить текст вашего displayButtonAction нажатие кнопки которого равно nil.

Внутри addButtonAndLabels() присваивание addButtonAndLabels() метки вашей основной метке в основной области контроллера вида с помощью:

self.displayButtonAction = displayButtonAction

вы начнете в правильном направлении.

Используя инструменты отладчика, точки останова и po - ваши друзья в таких ситуациях.

+3
источник

Главное, что я заметил, это то, что вы пытаетесь установить текст для метки в фоновом режиме. Вы никогда не должны создавать изменения пользовательского интерфейса ни на чем, кроме основной очереди, поэтому измените это на основную очередь следующим образом:

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

Вы должны получать предупреждения в отладчике, рассказывая об этом тоже.

Вы также должны бросить displayButtonAction останова внутри этой функции, чтобы убедиться, что displayButtonAction не равен нулю, и что у него есть frame который фактически находится на экране и имеет ненулевой размер. Для этого хорошо используйте этот отладчик.

+2
источник
другие ответы

Связанные вопросы


Похожие вопросы

Вы не можете обновлять элементы интерфейса на фоне (асинхронных) потоках. Для этого вам нужно получить основной поток.

DispatchQueue.main.async(execute: {
    self.label.text = "some text"
})
+1
источник

Посмотрите другие вопросы по меткам или Задайте вопрос