LoginSignup
9
6

More than 5 years have passed since last update.

Swiftでメタプロっぽい事をする

Last updated at Posted at 2016-04-17

GetWild退勤的なセンサーアプリを簡単に作れるフレームワークを作ったのでiPhoneに歯痛を心配されたり色々する

で得た知見シリーズ

文字列のクラス名からインスタンスを生成する

public func NSClassFromString(aClassName: String) -> AnyClass?

を使う。

@objc(Hoge)
class Hoge: NSObject, FugaProtocol {
}
let className = "Hoge"
let cls = NSClassFromString(className) as! NSObject.Type
instance = (cls.init() as! FugaProtocol)

生成対象にするクラスはNSObjectを継承していて、かつ@objcを付けていないといけない。

動的にpropertyを追加する

public func objc_setAssociatedObject(object: AnyObject!, _ key: UnsafePointer<Void>, _ value: AnyObject!, _ policy: objc_AssociationPolicy)

public func objc_getAssociatedObject(object: AnyObject!, _ key: UnsafePointer<Void>) -> AnyObject!

を使う

import Foundation

protocol dynamicStoredPropertyProtocol {
    func setDynamicStoredProperty(propertyName: String, propertyValue: AnyObject)
    func getDynamicStoredProperty(propertyName: String) -> AnyObject?
}

extension dynamicStoredPropertyProtocol where Self: NSObject {
    func setDynamicStoredProperty(propertyName: String, propertyValue: AnyObject) {
        if !hasDynamicStoredPropertyContainer() {
            initDynamicStoredPropertyContainer()
        }

        var container = getDynamicStoredPropertyContainer()
        container![propertyName] = propertyValue
        setDynamicStoredPropertyContainer(container!)
    }

    func getDynamicStoredProperty(propertyName: String) -> AnyObject? {
        guard var container = getDynamicStoredPropertyContainer() else {
            return nil
        }
        return container[propertyName]
    }

    func initDynamicStoredPropertyContainer() {
        setDynamicStoredPropertyContainer([:])
    }

    func setDynamicStoredPropertyContainer(container: Dictionary<String, AnyObject>) {
        objc_setAssociatedObject(self, &containerPointer, container, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }

    func getDynamicStoredPropertyContainer() -> Dictionary<String, AnyObject>? {
        return objc_getAssociatedObject(self, &containerPointer) as? Dictionary<String, AnyObject>
    }

    func hasDynamicStoredPropertyContainer() -> Bool {
        guard (getDynamicStoredPropertyContainer() != nil) else {
            return false
        }
        return true
    }    
}

private var containerPointer:UInt8 = 0

元気とランタイムAPIがあれば何でもできる。

ここまで書いておいてあれだけれど、コンパイル時に分からず実行してみないと分からない事が増えたり、計測してないけどランタイムAPIを使うとパフォーマンスどうなんだろうという懸念があったりするので、普通のアプリケーションでは使わない方が良いと思う。

参考にしたもの

9
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
6