Nice programing

NSDictionaryOfVariableBindings 신속하게 대응합니까?

nicepro 2020. 12. 1. 19:46
반응형

NSDictionaryOfVariableBindings 신속하게 대응합니까?


Apple 문서는 여기 UIKit 참조의 'Creating a Dictionary'섹션 아래에 불안정한 공백을 표시합니다 .

NSDictionaryOfVariableBindings매크로 대체품을 찾은 사람 이 있습니까? 아니면 우리가 직접 작성해야합니까?

편집 -에 따르면 아마도 올바른 접근 방식이 처리 할 수있는 전역 함수를 작성하는 것입니다? 복잡한 매크로가 완전히 사라진 것 같습니다.


Apple 소스 코드에 따르면 :

NSDictionaryOfVariableBindings (v1, v2, v3)는 [NSDictionary dictionaryWithObjectsAndKeys : v1, @ "v1", v2, @ "v2", v3, @ "v3", nil]과 동일합니다.

따라서 Swift에서 다음을 사용하여 동일한 작업을 수행 할 수 있습니다.

let bindings = ["v1": v1, "v2": v2, "v3": v3]

NSDictionaryOfVariableBindings말씀하신대로 매크로입니다. Swift에는 매크로가 없습니다. 너무 많이.

그럼에도 불구하고 Swift 함수를 쉽게 작성하여 사전의 뷰에 문자열 이름을 할당 한 다음 해당 사전을 constraintsWithVisualFormat. 차이점은 오브젝티브 C는 달리, 스위프트가 볼 수 있다는 것이다 당신의 그 뷰의 이름을; 당신은 수 있도록해야 할 것이다 구성하는 몇 가지 새로운 이름을.

[명확하게 말하자면, Objective-C 코드 가 변수 이름을 볼 수 있다는 것은 아닙니다 . 매크로 평가시 전처리 기가 소스 코드 에서 텍스트 로 작동 하고 다시 작성했기 때문에 따옴표 안에 (문자열을 만들기 위해)와 바깥 쪽 (값을 만들기 위해) 모두 변수 이름의 텍스트를 사용할 수 있습니다. 사전을 만드십시오. 그러나 Swift에는 전처리 기가 없습니다.]

그래서, 내가하는 일은 다음과 같습니다.

func dictionaryOfNames(arr:UIView...) -> Dictionary<String,UIView> {
    var d = Dictionary<String,UIView>()
    for (ix,v) in arr.enumerate(){
        d["v\(ix+1)"] = v
    }
    return d
}

그리고 당신은 그것을 호출하고 다음과 같이 사용합니다.

    let d = dictionaryOfNames(myView, myOtherView, myFantasicView)
    myView.addConstraints(
        NSLayoutConstraint.constraintsWithVisualFormat(
            "H:|[v2]|", options: nil, metrics: nil, views: d)
    )

문제는 시각적 형식 문자열 의 이름 (에 전달 된 목록에서 두 번째이기 때문에) 라는 것을 인식하는 것은 사용자 에게 달려 있다는 것입니다 . 하지만 매번 손으로 사전을 타이핑하는 지루함을 피하기 위해 그렇게 살 수 있습니다.myOtherViewv2dictionaryOfNames()

물론 Objective-C에서 이와 동일한 함수를 거의 작성했을 수도 있습니다. 매크로가 이미 존재했기 때문에 귀찮게하지 않았을뿐입니다!


이 기능은 현재 Swift에서 지원되지 않는 매크로 확장을 기반으로합니다.

나는 현재 Swift에서 비슷한 것을 할 수있는 방법이 없다고 생각합니다. 나는 당신이 자신의 대체물을 쓸 수 없다고 믿습니다.

각 이름을 두 번 반복하는 경우에도 사전 정의를 수동으로 풀어야합니다.


ObjC 런타임을 구출하십시오!

대체 솔루션을 만들었지 만 각 뷰가 동일한 객체의 인스턴스 변수 인 경우에만 작동합니다.

func DictionaryOfInstanceVariables(container:AnyObject, objects: String ...) -> [String:AnyObject] {
    var views = [String:AnyObject]()
    for objectName in objects {
        guard let object = object_getIvar(container, class_getInstanceVariable(container.dynamicType, objectName)) else {
            assertionFailure("\(objectName) is not an ivar of: \(container)");
            continue
        }
        views[objectName] = object
    }
    return views
}

다음과 같이 사용할 수 있습니다.

class ViewController: UIViewController {

    var childA: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = UIColor.redColor()
        return view
    }()

    var childB: UIButton = {
        let view = UIButton()
        view.setTitle("asdf", forState: .Normal)
        view.translatesAutoresizingMaskIntoConstraints = false
        view.backgroundColor = UIColor.blueColor()
        return view
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.view.addSubview(childA)
        self.view.addSubview(childB)

        let views = DictionaryOfInstanceVariables(self, objects: "childA", "childB")
        self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[childA]|", options: [], metrics: nil, views: views))
        self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[childB]|", options: [], metrics: nil, views: views))
        self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[childA][childB(==childA)]|", options: [], metrics: nil, views: views))

    }

}

안타깝게도 변수 이름을 문자열로 입력해야하지만 적어도 오타가 있으면 단언합니다. 이것은 모든 상황에서 확실히 작동하지는 않지만 그럼에도 불구하고 도움이됩니다.


그래서 나는 작동하는 것처럼 보이는 것을 함께 해킹했습니다.

func dictionaryOfVariableBindings(container: Any, views:UIView...) -> Dictionary<String, UIView> {
    var d = Dictionary<String, UIView>()
    let mirror = Mirror(reflecting: container)
    let _ = mirror.children.compactMap {
        guard let name = $0.label, let view = $0.value as? UIView else { return }
        guard views.contains(view) else { return }
        d[name] = view
    }
    return d
}

용법:

        let views = dictionaryOfVariableBindings(container: self, views: imageView)


모든 뷰를 속성으로 저장하면 다음과 같이 리플렉션을 사용할 수도 있습니다.

extension ViewController {
    func views() -> Dictionary<String, AnyObject> {
        var views = dictionaryOfProperties()
        views.forEach {
            if !($1 is UIView) {
                views[$0] = nil
            }
        }
        return views
    }
}

extension NSObject {

    func dictionaryOfProperties() -> Dictionary<String, AnyObject> {
        var result = Dictionary<String, AnyObject>()
        let mirror = Mirror(reflecting: self)
        for case let(label?, value) in mirror.children {
            result[label] = value as? AnyObject
        }
        return result
    }
}

cherpak-evgeny의 https://stackoverflow.com/a/55086673/1058199기반 으로이 UIViewController 확장은 컨테이너가 self현재 viewController 인스턴스 인 것으로 가정 합니다.

extension UIViewController {

    // Alex Zavatone 06/04/2019
    // Using reflection, get the string name of the UIView properties passed in
    // to create a dictionary of ["viewPropertyName": viewPropertyObject…] like
    // Objective-C's NSDictionaryForVariableBindings.
    func dictionaryOfBindings(_ arrayOfViews:[UIView?]) -> Dictionary<String, UIView> {
        var bindings = Dictionary<String, UIView>()
        let viewMirror = Mirror(reflecting: self)
        let _ = viewMirror.children.compactMap {
            guard let name = $0.label, let view = $0.value as? UIView else { return }
            guard arrayOfViews.contains(view) else { return }
            bindings[name] = view
        }
        return bindings
    }
}

viewController 내에서 다음과 같이 사용하십시오.

let viewArray = [mySwitch, myField, mySpinner, aStepper, someView]
let constraintsDictionary = dictionaryOfBindings(viewArray)

Xcode 10.2.1 및 Swift 4.2에서 테스트되었습니다.

Many thanks to Cherpak Evgeny for writing it in the first place.

참고URL : https://stackoverflow.com/questions/24085140/nsdictionaryofvariablebindings-swift-equivalent

반응형