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)
)
문제는 시각적 형식 문자열 의 이름 이 (에 전달 된 목록에서 두 번째이기 때문에) 라는 것을 인식하는 것은 사용자 에게 달려 있다는 것입니다 . 하지만 매번 손으로 사전을 타이핑하는 지루함을 피하기 위해 그렇게 살 수 있습니다.myOtherView
v2
dictionaryOfNames()
물론 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
'Nice programing' 카테고리의 다른 글
매우 느린 이클립스 4.2, 반응 속도를 높이는 방법은 무엇입니까? (0) | 2020.12.01 |
---|---|
특정 시간 후에 다른 HTML 페이지를로드하고 싶습니다. (0) | 2020.12.01 |
동일한 폴더에 go 파일 가져 오기 (0) | 2020.12.01 |
LocalDate 인스턴스를 비교하는 방법 Java 8 (0) | 2020.12.01 |
RSA 개인 키 암호는 내부에서 어떻게 작동합니까? (0) | 2020.12.01 |