【问题标题】:Setting text of UILabel from notification works on simulator but not physical device从通知中设置 UILabel 的文本适用于模拟器,但不适用于物理设备
【发布时间】:2019-04-19 05:26:45
【问题描述】:

我有一个简单的应用程序,当用户点击本地推送通知时,它会更新 UILabel。在模拟器中,当我点击通知时,会调用 applicationDidBecomeActive ,其中,我有一个引用视图控制器类的共享对象。然后我调用该类中的函数来获取新字符串并将 UILabel 设置为所述字符串。

这在模拟器中一直有效,但是当我将应用程序加载到我的设备上时,它会在前几次有效,然后停止。

我知道设备正在更新字符串值,因为当我切换到应用程序中的另一个视图并切换回来时,UILabel 现在会显示正确更新的值,但从通知返回时不会显示。

有没有其他人遇到过模拟器和物理设备行为不同的问题?

这里的要求是一些希望有帮助的代码:

这是来自 appDelagate.swift 文件

func applicationDidBecomeActive(_ application: UIApplication) {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    fetchCurrentUnQuoteFromViewController()
    print("applicationDidBecomeActive has finished running.")
}

//Custom functions for the delagate
func setDefaultToTrue() {
    readyForNewUnQuote = true
    defaults.setValue(readyForNewUnQuote, forKey: "readyForNewUnQuote")
}

func fetchCurrentUnQuoteFromViewController() {
    let quoteViewController:QuoteViewController = window!.rootViewController as! QuoteViewController
    quoteViewController.getRandomGradient()
    quoteViewController.fetchRandomUnQuote()
}

在我的视图控制器中,这里是从 appDelagate 调用的函数

func getRandomGradient() {
    let randomNumber: Int = Int.random(in: 0 ... gradientArray.count - 1)
    QuoteGradient.image = UIImage(named: gradientArray[randomNumber])
}

func updateUI() {
    unQuoteLabel.text = defaults.string(forKey: "currentQuote")
}

编辑:我基本上添加了 viewController.viewDidLoad() 作为一个额外的调用,这似乎是有效的。这是一个糟糕的电话吗?这似乎是一种解决问题的骇人听闻的方式。

好的,我想我已经进一步缩小了范围。我有第二个视图,我试图将其用于设置页面。如果我只保留引用文本的第一个视图,那么当弹出通知时,我可以点击它,它将更新为设置的新文本。

但是,如果我转到设置视图然后返回报价视图,那么当我点击通知时它不会更新文本,直到我返回设置页面然后再次返回报价页面。

我是 iOS 开发的新手,我真的不知道转到新视图是否会对我正在创建的共享对象产生任何影响,或者它是否会产生我不知道的其他事情。

编辑 2:这是用户点击通知时触发的函数:

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    setDefaultToTrue()
    print(defaults.value(forKey: "readyForNewUnQuote") ?? "Error")

    fetchCurrentUnQuoteFromViewController()

    print("response from notification was fired.")

    completionHandler()
}

【问题讨论】:

  • 您必须提供一些代码。是的,模拟器和物理设备在某些方面确实表现不同。
  • @MikeTaverne 我已经用一些代码更新了我的问题,希望对这项调查有所帮助。
  • 如果应用程序被终止,那么您可能需要签入 didFinishLaunching。您可以在那里检查有效负载。我相信您可以检查一些问题
  • @agibson007 发生这种情况时,应用程序不会被杀死。它只是在后台处于非活动状态。
  • @Puddinglord didReceiveLocalNotification 函数在哪里。你也应该在那里处理事情。

标签: ios swift ios-simulator


【解决方案1】:

试一试。我有一段时间没有使用本地通知,但您似乎可以检查通知中心的代表是否接受警报。

import UIKit
import UserNotifications

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    let handler = NotificationHandler()
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        handler.appDelegate = self
        let center = UNUserNotificationCenter.current()
        center.delegate = handler
        return true
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.

    }
}

class NotificationHandler: NSObject, UNUserNotificationCenterDelegate {
    var appDelegate : AppDelegate?
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification,
                                withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        // Play sound and show alert to the user
        completionHandler([.alert,.sound])
    }

    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler completionHandler: @escaping () -> Void) {

        switch response.actionIdentifier {
        case UNNotificationDismissActionIdentifier:
            print("Dismiss Action")
        case UNNotificationDefaultActionIdentifier:
            print("we are launching")
            if let app = appDelegate,
                let root = app.window?.rootViewController as? ViewController{
                print("we have the info")
                root.titleLabel.text = response.notification.request.content.title
                root.bodyLabel.text = response.notification.request.content.body
            }
        case "Snooze":
            print("Snooze")
        case "Delete":
            print("Delete")
        default:
            print("Unknown action")
        }
        completionHandler()
    }
}


import UIKit
import UserNotifications

class ViewController: UIViewController {

    let center = UNUserNotificationCenter.current()

    lazy var titleLabel : UILabel = {
        let lbl = UILabel(frame: CGRect(x: 20, y: 0, width: self.view.bounds.width - 40, height: 50))
        lbl.textColor = .black
        lbl.font = UIFont.systemFont(ofSize: 20)
        lbl.numberOfLines = 0
        lbl.textAlignment = .center
        return lbl
    }()

    lazy var bodyLabel : UILabel = {
        let lbl = UILabel(frame: CGRect(x: 20, y: titleLabel.frame.maxY, width: self.view.bounds.width - 40, height: 50))
        lbl.textColor = .black
        lbl.font = UIFont.systemFont(ofSize: 20)
        lbl.numberOfLines = 0
        lbl.textAlignment = .center
        return lbl
    }()


    override func viewDidLoad() {
        super.viewDidLoad()

        self.view.addSubview(titleLabel)
        titleLabel.center = self.view.center
        titleLabel.text = "We are just getting started"
        self.view.addSubview(bodyLabel)

        let options: UNAuthorizationOptions = [.alert, .sound]
        center.requestAuthorization(options: options) {
            (granted, error) in
            if !granted {
                print("Something went wrong")
            }
        }

        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2.0) {
            self.center.removeAllDeliveredNotifications()
            self.center.removeAllPendingNotificationRequests()
            self.setNotificationWith(title: "Party", contentBody: "Party like it's 1999")
        }
    }

    func setNotificationWith(title:String,contentBody:String){
        let content = UNMutableNotificationContent()
        content.title = title
        content.body = contentBody
        content.sound = UNNotificationSound.default

        let date = Date(timeIntervalSinceNow: 60)
        let triggerDate = Calendar.current.dateComponents([.year,.month,.day,.hour,.minute,.second,], from: date)

        let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDate,
                                                    repeats: false)

        let identifier = "NotificationTest"
        let request = UNNotificationRequest(identifier: identifier,
                                            content: content, trigger: trigger)
        center.add(request, withCompletionHandler: { (error) in
            if let error = error {
                // Something went wrong
                print("we have an error \(error)")
            }
        })
    }
}

【讨论】:

  • 我已经添加了您提供的委托,现在我可以看到用户何时点击通知。现在的问题是当我切换到另一个视图,即设置页面然后切换回来时,现在通知不再实时更新 UILabel。如果我在点击通知后切换视图,UILabel 会更新,但在点击通知时不会更新。
  • 我需要更多信息。您是说您正在查看屏幕并点按您要在上一屏幕中切换信息的通知?
  • 我有两种观点。主页面和设置页面。它们通过 segues 连接。当我启动应用程序时,我可以回家并收到通知,当我点击它时,主页将更新我想要的新报价。如果我启动应用程序并转到设置页面然后返回主页,回家然后收到通知,应用程序将恢复到主页但 UILabel 不会更新。现在只有当我点击设置按钮然后返回到引用所在的主视图时才会更新。
  • 你能告诉我或告诉我你在哪里调用 UI 更新吗?
【解决方案2】:

我已经解决了我的问题!问题在于我在情节提要中使用的转场。

我改变了它,而不是使用视觉 segues,当我按下设置按钮时,我在这里运行这个函数,它从情节提要的视图中加载,然后将其呈现给用户。然后我在设置页面上有另一个按钮可以关闭该页面。

@IBAction func settingsButtonAction(_ sender: UIButton) {
    let controller = storyboard?.instantiateViewController(withIdentifier: "SettingsViewController") as! SettingsViewController
    present(controller, animated: true, completion: nil)
}

我不知道为什么这会导致问题,因为我对 swift 和 iOS 开发还是新手,但从现在开始,我不会使用故事板向用户呈现不同的视图。我现在只会使用present和dismiss函数。

【讨论】:

  • 诚实吗?这是一个可以提问的公共场所,我做到了。也让人们帮助回答你做了什么。你没有完全解决我的问题不是我的错。抱歉,我没有给您您迫切需要的绿色复选标记。我特别说我是 swift 和 iOS 开发的新手,所以是的,我的理念很糟糕。但是,您没有帮助我理解我的哲学,而是决定对此无礼。我想谢谢你没有任何意义。注意到朋友。
  • 嗯,这只是问题与答案无关。此处不应有绿色复选标记。在早期的 cmets 中,我感到你的短促。也许我读错了,文本很难解释。我很高兴你修好了。祝学习顺利。当我进入它一段时间后,我可能会很短,对此我感到很抱歉。我也去过那里。不过故事板很好。您只需将数据传递给属性并在 viewWillAppear 或某处进行更新。
  • 我很感激我真的非常感谢。我同意答案与问题无关。祝你好运!
  • 只是另一个提示。我敢打赌,即使解雇,您也会继续使用 perform segue。当您关闭时,您可以使用与代码相同的方式关闭情节提要 Vc。 dismissVC 或 popView 取决于它的呈现方式
  • 我确实在使用 preform segue 来关闭设置页面,因为我不知道以不同的方式进行操作。感谢您的提示!
猜你喜欢
  • 1970-01-01
  • 2019-11-09
  • 2012-11-01
  • 2011-03-08
  • 2015-02-13
  • 2011-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多