

アーロン・ヒレガスの MAC OS X COCOA プログラミングのサンプルを Swiftで書き直していて、表題のところで詰まっています。

「各クラスは、何らかのメッセージを受信する前に
initializeというメッセージを受け取ります」とあり、swiftでこのクラスメソッドを実装しようと以下のようなコードを書いてみたのですが、

[code]

    import Foundation
    
    class AClass : NSObject {
        override class func initialize() {
            print ("initialized")
        }
    
        func hello() {
            print("hello")
        }
    }
    
    let a1 = AClass()
    let a2 = AClass()
    
    a1.hello()
    a2.hello()
    
    // 以下のような結果になってほしい
    // initialized
    // hello
    // hello
    
    
[/code]

結果は

> Method 'initialize() defines Objective-C class method 'initialize', which is
> not permitted by Swift

というエラーとなりました。

not permittedなのは仕方がないので別の方法を探しているのですが、何か良い方法はございませんか?


CC BY-SA 4.0
2019-12-04T06:30:12.543
61089
2019-12-05T07:10:43.583
2957
question
swift swift5
objcの クラスメソッド initialize相当の処理を Swiftで行う方法


Swiftの開発陣が`initialize`や`load`なんかのObjective-
Cのクラスメソッドを禁止にしたのは、動作が実行環境や実行状態など非決定的な要因で変化してしまい、確実な動作保証をするのが難しいからと言うことだったと思います。(残念ながらその辺りの議論の跡をすぐに見つけることはできませんでした。)

「クラスの初期化」的な動作をさせたければ、初期化メソッドを用意して、アプリの起動時などに明示的にその初期化メソッドを呼んでやる、と言うのがSwift流と言うことになるのだろうと思います。

上記したように「最初のメソッドを呼び出す前(`initialize`)」(ただし、どの程度「前」かはよくわからない)なんて挙動をSwiftで再現することは難しいですが、「最初のインスタンスを使用する前」くらいでよければ、こんな感じで実現できます。

[code]

    import Foundation
    
    class AClass : NSObject {
        private static let initialization: Void = {
            print ("initialized")
        }()
    
        override init() {
            _ = AClass.initialization
        }
    
        func hello() {
            print("hello")
        }
    }
    
    let a1 = AClass()
    let a2 = AClass()
    
    a1.hello()
    a2.hello()
    
[/code]

実行結果

>
[code]

>     initialized
>     hello
>     hello
>  
[/code]

Objective-
CのコードをSwiftで書き直す、と言う練習は、Swift言語の学習の上でも効果的な手法の一つだと思いますが、「Swiftの文法でObjective-
C的コードを書いてしまいがちになる」なんて弊害もあります。常に「これはSwift的なコードなのか?」なんてことを考える癖をつけると良いだろうと思います。


CC BY-SA 4.0
2019-12-04T12:46:41.020
61104
2019-12-04T12:46:41.020
13972
61089
answer


自分で調べた書き方

参考 : <https://tech-blog.sgr-ksmt.org/2016/09/25/once_closure/>

[code]

    fileprivate typealias OnceClosure = (() -> Void)?
    fileprivate func execute_once(_ execute: () -> Void) -> OnceClosure {
        execute()
        return {return nil}()
    }
    
    class AClass : NSObject {
        fileprivate static var exec_once : OnceClosure = execute_once {
            print("initialized")
        }
    
        override init() {
            super.init()
            AClass.exec_once?()
        }
    
        func hello() {
            print("hello")
        }
    }
    
[/code]


CC BY-SA 4.0
2019-12-05T07:10:43.583
61129
2019-12-05T07:10:43.583
2957
61089
answer