56249


アプリをインストールした直後に一回だけ NavigationBar のタイトルを決める処理をしたいのですが書いたコードが実行されない理由はなんですか？
又、どの様にしたら実行される様になりますか?

[![画像の説明をここに入力](https://i.stack.imgur.com/oNcFJ.png)](https://i.stack.imgur.com/oNcFJ.png)

[code]

    import UIKit
    
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
        static let share = AppDelegate()
    
        var window: UIWindow?
    
        var theFarstNameDidSet : ((_ nowNumber : String) -> Void)? = nil
        var theFarstBool = false
    
        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { //ここが初回起動のコードらしい。
    
            // Override point for customization after application launch.
            print("最初に実行")
            self.theFarstBool = true
            self.theFarstNameDidSet?("")
            print("最後に実行")
            self.theFarstBool = false
            return true
        }
    
        func applicationWillResignActive(_ application: UIApplication) {
            // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
            // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
        }
    
        func applicationDidEnterBackground(_ application: UIApplication) {
            // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
            // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
        }
    
        func applicationWillEnterForeground(_ application: UIApplication) {
            // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
        }
    
        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.
        }
    
        func applicationWillTerminate(_ application: UIApplication) {
            // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
        }
    
    
    }
    
[/code]

[code]

    import UIKit
    
    
    class ViewController: UIViewController {
    
    
        @IBOutlet weak var characterImage: UIImageView!
        @IBOutlet weak var timerlabel: UILabel!
        @IBOutlet weak var startButton: UIButton!
    
        let userDefaults = UserDefaults.standard
        let fastTitleKey = "fastTitleKey"
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
    
            startButton.layer.cornerRadius = 25.0
    
            guard let obj = UserDefaults.standard.object(forKey: "goalCountKey") else {
                return
            }
    
            let goalString = "\(obj)"
            timerlabel.text = secondsToGoalTimerLabel(Int(goalString)!)
    
            if AppDelegate.share.theFarstBool == true {
                print("２番目に実行")
                AppDelegate.share.theFarstNameDidSet = { nowNumber in
                    var alertTextFeld: UITextField?
                    let alert = UIAlertController(title: "Skill Name", message: "Enter new name", preferredStyle: UIAlertController.Style.alert)
                    alert.addTextField { (textField: UITextField!) in
                        alertTextFeld = textField
                    }
    
                    alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in
                        if let text = alertTextFeld?.text {
                           self.title = text
                            self.userDefaults.set(text, forKey: self.fastTitleKey)
                            self.userDefaults.synchronize()
    
                        }
                    }))
                    self.present(alert, animated: true, completion: nil)
                }
    
            }
    
    
            self.title = self.userDefaults.object(forKey: self.fastTitleKey) as? String
    
         }
    
        override func viewWillAppear(_ animated: Bool) {
    
            guard let obj = UserDefaults.standard.object(forKey: "goalCountKey") else {
                return
            }
    
            let goalString = "\(obj)"
            timerlabel.text = secondsToGoalTimerLabel(Int(goalString)!)
        }
    
    }
    
    
    
[/code]


CC BY-SA 4.0
2019-06-29T09:42:03.043
56228
2019-06-30T08:05:18.750
34541
question
swift xcode
アプリの初回起動の限定の処理について


奇跡的にできました。  
UserDefaultsを使ったらできました。 なんで機能しているのかよくわかっていないのですが。わかる方がいらしたら教えてください。

[code]

    import UIKit
    
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
        static let share = AppDelegate()
    
        var window: UIWindow?
    
        let userDefaults = UserDefaults.standard
        let theFarstBoolKey = "theFastBoolKey"
    
        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
            // Override point for customization after application launch
    
            userDefaults.register(defaults: [theFarstBoolKey : true])  //ここが大切な気がします。
    
            if userDefaults.object(forKey: theFarstBoolKey) as! Bool == true {
    
            userDefaults.set(true, forKey: theFarstBoolKey)
            userDefaults.synchronize()
    
            } else {
    
            userDefaults.set(false, forKey: theFarstBoolKey)
            userDefaults.synchronize()
            }
    
    //        if userDefaults.object(forKey: theFarstBoolKey) as! Bool == true {
    //        }
    
            return true
        }
    
        func applicationWillResignActive(_ application: UIApplication) {
            // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
            // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
        }
    
        func applicationDidEnterBackground(_ application: UIApplication) {
            // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
            // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
        }
    
        func applicationWillEnterForeground(_ application: UIApplication) {
            // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
        }
    
        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.
        }
    
        func applicationWillTerminate(_ application: UIApplication) {
            // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
        }
    
    
    }
    
    
    
    
[/code]

[code]

    import UIKit
    
    
    class ViewController: UIViewController {
    
    
        @IBOutlet weak var characterImage: UIImageView!
        @IBOutlet weak var timerlabel: UILabel!
        @IBOutlet weak var startButton: UIButton!
    
        let userDefaults = UserDefaults.standard
        let fastTitleKey = "fastTitleKey"
    
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
    
            if AppDelegate.share.userDefaults.object(forKey: "theFastBoolKey") as! Bool == true {  // 変更したのはここです
    
                var alertTextFeld: UITextField?
                let alert = UIAlertController(title: "Skill Name", message: "Enter new name", preferredStyle: UIAlertController.Style.alert)
                alert.addTextField { (textField: UITextField!) in
                    alertTextFeld = textField
                }
                alert.addAction(UIAlertAction(title: "キャンセル", style: .cancel, handler: nil))
                alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in
                    if let text = alertTextFeld?.text {
                        self.title = text
                        self.userDefaults.set(text, forKey: self.fastTitleKey)
                        self.userDefaults.synchronize()
                    }
                }))
    
                self.present(alert, animated: true, completion: nil)
    
                AppDelegate.share.userDefaults.set(false, forKey: "theFastBoolKey")
                AppDelegate.share.userDefaults.synchronize()
            }
    
            self.title = self.userDefaults.object(forKey: self.fastTitleKey) as? String
    
            startButton.layer.cornerRadius = 25.0
    
            guard let obj = UserDefaults.standard.object(forKey: "goalCountKey") else {
                return
            }
    
            let goalString = "\(obj)"
            timerlabel.text = secondsToGoalTimerLabel(Int(goalString)!)
    
    
         }
    
        override func viewWillAppear(_ animated: Bool) {
    
            guard let obj = UserDefaults.standard.object(forKey: "goalCountKey") else {
                return
            }
    
            let goalString = "\(obj)"
            timerlabel.text = secondsToGoalTimerLabel(Int(goalString)!)
        }
    
    
    
    }
    
[/code]

`func application(_ application: UIApplication, didFinishLaunchingWithOptions
launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool`
の中の処理ですがまだまだ無駄が多い様に思われます。優れたコードとはかけ離れたコードだと思うのですが動いたのでまぁよしとします。


CC BY-SA 4.0
2019-06-30T06:31:39.430
56243
2019-06-30T06:31:39.430
34541
56228
answer


クラス`UserDefaults`の処理だけで、目的の処理を実現できます。

[code]

    import UIKit
    
    class ViewController: UIViewController {
    
        private let titleKey = "ViewTitle"
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            if let myTitle = UserDefaults.standard.string(forKey: titleKey) {
                self.title = myTitle
            } else {
                let alert = UIAlertController(title: "Title Name", message: "Input title string", preferredStyle: .alert)
                alert.addTextField(configurationHandler: nil)
                alert.addAction(UIAlertAction(title: "OK", style: .default, handler: {_ in
                    if let text = alert.textFields?[0].text {
                        self.title = text
                        UserDefaults.standard.set(text, forKey: self.titleKey)
                    }
                }))
                alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
                present(alert, animated: true, completion: nil)
            }
        }
    
    }
    
[/code]

`UserDefaults.standard.string(forKey:
titleKey)`が`nil`を返してきたなら、アプリのインストール後、初めての起動と判断できます。「初回起動」の処理をして、`UserDefaults.standard.set(text,
forKey: self.titleKey)`でキーと値をセットします。

* * *

[`UserDefaults`クラスのメソッド`synchronize()`](https://developer.apple.com/documentation/foundation/userdefaults/1414005-synchronize)のリファレンスに、「使う必要がないから、使うな」と書かれているので、このメソッドは使わないでください。初期設定ファイルへの保存は、`UserDefaults`クラスが、よしなに処理してくれます。iOS以前のMac
OS X
10.0の時代、あるいはさらに以前のNextStepの時代、`NSUserDefaults`の動作の信頼性が低かったため、おそらくこのメソッドが用意されていたのではないかと、推測します。

* * *

> func application(_ application: UIApplication, didFinishLaunchingWithOptions
> launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {  
>  //ここが初回起動のコードらしい。

この推測は、まったくの見当違いです。初回かどうかは関係なく、アプリケーションの起動が完了した時に、つねにこのデリゲートメソッドが呼び出されます。シミュレータを使って、この検証はかんたんに行えますので、暇な時間、調べてみてください。

* * *
[code]

    class AppDelegate: UIResponder, UIApplicationDelegate {
        static let share = AppDelegate()
    
[/code]

既存のクラスをシングルトン化することは、（今回副作用が起きていないからといっても）危険なので、やめてください。  
とくに`AppDelegate`クラスは、`UIApplication.shared`インスタンスが、その内部で`AppDelegate`クラスからインスタンスを生成し、自らのデリゲート先に指定しています。

iOSのアプリ開発が、一般に公開された当初から、`AppDelegate`は、シングルトンと同等の働きをするものとして、多くのプログラマが利用していました（今もシングルトンとして利用しているプログラマは多いと思います）。まず、`UIApplication.shared`がシングルトンです。このシングルトンがデリゲート先として生成した`AppDelegate`のインスタンスは、プログラム上たったひとつだけ存在し、あらゆるオブジェクトから`UIApplication.shared.delegate`で参照可能であるということで、シングルトンの要件が満たされています。なので、

[code]

    UIApplication.shared.delegate as? AppDelegate
    
[/code]

これで参照して、`AppDelegate`インスタンスを利用してください。


CC BY-SA 4.0
2019-06-30T08:05:18.750
56249
2019-06-30T08:05:18.750
18540
56228
answer