Swift Language
연관된 객체들
수색…
프로퍼티 확장 내에서, 관련 객체를 사용하여 성취 된 속성.
스위프트에서 프로토콜 확장은 진정한 속성을 가질 수 없습니다.
그러나 실제로는 "관련 객체"기술을 사용할 수 있습니다. 결과는 거의 정확히 "실제"속성과 같습니다.
다음은 프로토콜 확장에 "관련 객체"를 추가하는 정확한 기술입니다.
근본적으로, "objc_getAssociatedObject"및 _set 호출과 같은 목적을 사용합니다.
기본 호출은 다음과 같습니다.
get {
return objc_getAssociatedObject(self, & _Handle) as! YourType
}
set {
objc_setAssociatedObject(self, & _Handle, newValue, .OBJC_ASSOCIATION_RETAIN)
}
전체 예제가 있습니다. 두 가지 중요한 포인트는 다음과 같습니다.
프로토콜에서 ": class"를 사용하여 변이 문제를 피하십시오.
확장 기능에서는 "Where Self : UIViewController"(또는 적절한 클래스)를 사용하여 확인 유형을 지정해야합니다.
따라서 예제 "p"속성의 경우 :
import Foundation
import UIKit
import ObjectiveC // don't forget this
var _Handle: UInt8 = 42 // it can be any value
protocol Able: class {
var click:UIView? { get set }
var x:CGFloat? { get set }
// note that you >> do not << declare p here
}
extension Able where Self:UIViewController {
var p:YourType { // YourType might be, say, an Enum
get {
return objc_getAssociatedObject(self, & _Handle) as! YourType
// HOWEVER, SEE BELOW
}
set {
objc_setAssociatedObject(self, & _Handle, newValue, .OBJC_ASSOCIATION_RETAIN)
// often, you'll want to run some sort of "setter" here...
__setter()
}
}
func __setter() { something = p.blah() }
func someOtherExtensionFunction() { p.blah() }
// it's ok to use "p" inside other extension functions,
// and you can use p anywhere in the conforming class
}
일치하는 클래스에서 이제 "p"속성을 "추가"했습니다.
준수하는 클래스에서 일반 속성을 사용하는 것처럼 "p"를 사용할 수 있습니다. 예:
class Clock:UIViewController, Able {
var u:Int = 0
func blah() {
u = ...
... = u
// use "p" as you would any normal property
p = ...
... = p
}
override func viewDidLoad() {
super.viewDidLoad()
pm = .none // "p" MUST be "initialized" somewhere in Clock
}
}
노트. 반드시 가상 속성을 초기화해야합니다.
Xcode 는 준수하는 클래스에서 "p"를 초기화 하도록 강요 하지 않습니다 .
확인 클래스의 viewDidLoad에서 "p"를 초기화하는 것이 중요합니다.
p는 실제로 계산 된 특성 이라는 것을 기억할 필요가 있습니다 . p는 실제로 구문 당 (syntactic sugar)과 함께 단지 두 개의 함수입니다. 컴파일러는 어떤 의미에서 p에 대해 일부 메모리를 할당하지 않습니다. 이런 이유로 Xcode가 "p 초기화"를 시행 할 것으로 기대하는 것은 의미가 없습니다.
사실, 더 정확하게 말하기 위해 "초기화하는 것처럼 처음으로 p를 사용하는"것을 기억해야합니다. (다시 말하지만, 그것은 viewDidLoad 코드에있을 가능성이 큽니다.)
그러한 getter에 관해서.
"p"의 값이 설정되기 전에 getter가 호출 되면 충돌 합니다.
이를 피하려면 다음과 같은 코드를 고려하십시오.
get {
let g = objc_getAssociatedObject(self, &_Handle)
if (g == nil) {
objc_setAssociatedObject(self, &_Handle, _default initial value_, .OBJC_ASSOCIATION)
return _default initial value_
}
return objc_getAssociatedObject(self, &_Handle) as! YourType
}
반복합니다. Xcode 는 준수 클래스에서 p를 초기화 하도록 강요 하지 않습니다 . 일치하는 클래스의 viewDidLoad에서 p를 초기화하는 것이 중요합니다.
코드 단순화 ...
다음 두 가지 전역 함수를 사용할 수 있습니다.
func _aoGet(_ ss: Any!, _ handlePointer: UnsafeRawPointer!, _ safeValue: Any!)->Any! {
let g = objc_getAssociatedObject(ss, handlePointer)
if (g == nil) {
objc_setAssociatedObject(ss, handlePointer, safeValue, .OBJC_ASSOCIATION_RETAIN)
return safeValue
}
return objc_getAssociatedObject(ss, handlePointer)
}
func _aoSet(_ ss: Any!, _ handlePointer: UnsafeRawPointer!, _ val: Any!) {
objc_setAssociatedObject(ss, handlePointer, val, .OBJC_ASSOCIATION_RETAIN)
}
입력을 저장하고 코드를 읽기 쉽게 만드는 것 외에는 아무 것도하지 않습니다. 매크로는 본질적으로 매크로 또는 인라인 함수입니다.
그러면 코드가 다음과 같이됩니다.
protocol PMable: class {
var click:UILabel? { get set } // ordinary properties here
}
var _pHandle: UInt8 = 321
extension PMable where Self:UIViewController {
var p:P {
get {
return _aoGet(self, &_pHandle, P() ) as! P
}
set {
_aoSet(self, &_pHandle, newValue)
__pmSetter()
}
}
func __pmSetter() {
click!.text = String(p)
}
func someFunction() {
p.blah()
}
}
(_aoGet의 예제에서 P는 초기화 가능합니다. P () 대신 "", 0 또는 기본값을 사용할 수 있습니다.