itsource

Objective-C에서 내가 했던 것과 같은 방식으로 Swift에 자산을 저장하는 방법?

mycopycode 2023. 5. 17. 22:56
반응형

Objective-C에서 내가 했던 것과 같은 방식으로 Swift에 자산을 저장하는 방법?

애플리케이션을 Objective-C에서 Swift로 전환하고 있습니다. 여기에는 저장된 속성이 있는 몇 가지 범주가 있습니다. 예:

@interface UIView (MyCategory)

- (void)alignToView:(UIView *)view
          alignment:(UIViewRelativeAlignment)alignment;
- (UIView *)clone;

@property (strong) PFObject *xo;
@property (nonatomic) BOOL isAnimating;

@end

Swift 확장은 이러한 저장된 속성을 허용하지 않기 때문에 Objc 코드와 동일한 구조를 유지하는 방법을 모르겠습니다.저장된 속성은 제 앱에 매우 중요하며 Apple이 Swift에서 이를 수행하기 위한 솔루션을 만들었을 것이라고 생각합니다.

jou가 말했듯이, 제가 찾고 있던 것은 실제로 연관된 객체를 사용하는 것이었습니다. 그래서 저는 (다른 맥락에서) 다음과 같이 했습니다.

import Foundation
import QuartzCore
import ObjectiveC

extension CALayer {
    var shapeLayer: CAShapeLayer? {
        get {
            return objc_getAssociatedObject(self, "shapeLayer") as? CAShapeLayer
        }
        set(newValue) {
            objc_setAssociatedObject(self, "shapeLayer", newValue, UInt(OBJC_ASSOCIATION_RETAIN))
        }
    }

    var initialPath: CGPathRef! {
        get {
            return objc_getAssociatedObject(self, "initialPath") as CGPathRef
        }
        set {
            objc_setAssociatedObject(self, "initialPath", newValue, UInt(OBJC_ASSOCIATION_RETAIN))
        }
    }
}

그러나 다음 작업을 수행할 때 EXC_BAD_ACCESS가 표시됩니다.

class UIBubble : UIView {
    required init(coder aDecoder: NSCoder) {
        ...
        self.layer.shapeLayer = CAShapeLayer()
        ...
    }
}

아이디어 있어요?

Objective-C에서처럼 기존 클래스에 저장된 속성을 추가할 수 없습니다.클래스를 (목-C 래를확경는우하장스표클경(우▁if목▁an▁you)UIView는 확실히 하나입니다. 계속해서 연결된 개체를 사용하여 저장된 속성을 에뮬레이트할 수 있습니다.

스위프트 1의 경우

import ObjectiveC

private var xoAssociationKey: UInt8 = 0

extension UIView {
    var xo: PFObject! {
        get {
            return objc_getAssociatedObject(self, &xoAssociationKey) as? PFObject
        }
        set(newValue) {
            objc_setAssociatedObject(self, &xoAssociationKey, newValue, objc_AssociationPolicy(OBJC_ASSOCIATION_RETAIN))
        }
    }
}

연결 키는 각 연결에 대해 고유해야 하는 포인터입니다.위해 합니다.&교환입니다.Swift에서 포인터를 처리하는 방법에 대한 자세한 내용은 Swift를 코코아와 함께 사용목표-C를 참조하십시오.

Swift 2 및 3용으로 업데이트됨

import ObjectiveC

private var xoAssociationKey: UInt8 = 0

extension UIView {
    var xo: PFObject! {
        get {
            return objc_getAssociatedObject(self, &xoAssociationKey) as? PFObject
        }
        set(newValue) {
            objc_setAssociatedObject(self, &xoAssociationKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
        }
    }
}

Swift 4용으로 업데이트됨

스위프트 4에서는 훨씬 더 간단합니다.홀더 구조는 계산된 자산이 세상에 노출될 개인적인 가치를 포함하여 대신 저장된 자산 행동의 환상을 제공합니다.

원천

extension UIViewController {
    struct Holder {
        static var _myComputedProperty:Bool = false
    }
    var myComputedProperty:Bool {
        get {
            return Holder._myComputedProperty
        }
        set(newValue) {
            Holder._myComputedProperty = newValue
        }
    }
}

관련 개체 API는 사용하기가 좀 번거롭습니다.도우미 클래스로 대부분의 보일러 플레이트를 제거할 수 있습니다.

public final class ObjectAssociation<T: AnyObject> {

    private let policy: objc_AssociationPolicy

    /// - Parameter policy: An association policy that will be used when linking objects.
    public init(policy: objc_AssociationPolicy = .OBJC_ASSOCIATION_RETAIN_NONATOMIC) {

        self.policy = policy
    }

    /// Accesses associated object.
    /// - Parameter index: An object whose associated object is to be accessed.
    public subscript(index: AnyObject) -> T? {

        get { return objc_getAssociatedObject(index, Unmanaged.passUnretained(self).toOpaque()) as! T? }
        set { objc_setAssociatedObject(index, Unmanaged.passUnretained(self).toOpaque(), newValue, policy) }
    }
}

보다 읽기 쉬운 방법으로 objective-c 클래스에 속성을 "추가"할 수 있는 경우:

extension SomeType {

    private static let association = ObjectAssociation<NSObject>()

    var simulatedProperty: NSObject? {

        get { return SomeType.association[self] }
        set { SomeType.association[self] = newValue }
    }
}

솔루션의 경우:

extension CALayer {

    private static let initialPathAssociation = ObjectAssociation<CGPath>()
    private static let shapeLayerAssociation = ObjectAssociation<CAShapeLayer>()

    var initialPath: CGPath! {
        get { return CALayer.initialPathAssociation[self] }
        set { CALayer.initialPathAssociation[self] = newValue }
    }

    var shapeLayer: CAShapeLayer? {
        get { return CALayer.shapeLayerAssociation[self] }
        set { CALayer.shapeLayerAssociation[self] = newValue }
    }
}

그래서 글로벌 변수가 필요하지 않기 때문에 위의 방법보다 더 깨끗하게 작동하는 방법을 찾은 것 같습니다.저는 여기서 그것을 얻었습니다:

요점은 다음과 같은 구조를 사용한다는 것입니다.

extension UIViewController {
    private struct AssociatedKeys {
        static var DescriptiveName = "nsh_DescriptiveName"
    }

    var descriptiveName: String? {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.DescriptiveName) as? String
        }
        set {
            if let newValue = newValue {
                objc_setAssociatedObject(
                    self,
                    &AssociatedKeys.DescriptiveName,
                    newValue as NSString?,
                    UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC)
                )
            }
        }
    }
}

Swift 2용 업데이트

private struct AssociatedKeys {
    static var displayed = "displayed"
}

//this lets us check to see if the item is supposed to be displayed or not
var displayed : Bool {
    get {
        guard let number = objc_getAssociatedObject(self, &AssociatedKeys.displayed) as? NSNumber else {
            return true
        }
        return number.boolValue
    }

    set(value) {
        objc_setAssociatedObject(self,&AssociatedKeys.displayed,NSNumber(bool: value),objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
}

Jou가 지적한 솔루션은 가치 유형을 지원하지 않습니다. 이는 가치 유형과도 잘 작동합니다.

포장지

import ObjectiveC

final class Lifted<T> {
    let value: T
    init(_ x: T) {
        value = x
    }
}

private func lift<T>(x: T) -> Lifted<T>  {
    return Lifted(x)
}

func setAssociatedObject<T>(object: AnyObject, value: T, associativeKey: UnsafePointer<Void>, policy: objc_AssociationPolicy) {
    if let v: AnyObject = value as? AnyObject {
        objc_setAssociatedObject(object, associativeKey, v,  policy)
    }
    else {
        objc_setAssociatedObject(object, associativeKey, lift(value),  policy)
    }
}

func getAssociatedObject<T>(object: AnyObject, associativeKey: UnsafePointer<Void>) -> T? {
    if let v = objc_getAssociatedObject(object, associativeKey) as? T {
        return v
    }
    else if let v = objc_getAssociatedObject(object, associativeKey) as? Lifted<T> {
        return v.value
    }
    else {
        return nil
    }
}

가능한 클래스 확장(사용 예):

extension UIView {

    private struct AssociatedKey {
        static var viewExtension = "viewExtension"
    }

    var referenceTransform: CGAffineTransform? {
        get {
            return getAssociatedObject(self, associativeKey: &AssociatedKey.viewExtension)
        }

        set {
            if let value = newValue {
                setAssociatedObject(self, value: value, associativeKey: &AssociatedKey.viewExtension, policy: objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            }
        }
    }
}

이것은 정말 훌륭한 솔루션입니다. 저는 선택 사항이 아닌 구조와 값을 포함하는 다른 사용 예를 추가하고 싶었습니다.또한 AssociatedKey 값을 단순화할 수 있습니다.

struct Crate {
    var name: String
}

class Box {
    var name: String

    init(name: String) {
        self.name = name
    }
}

extension UIViewController {

    private struct AssociatedKey {
        static var displayed:   UInt8 = 0
        static var box:         UInt8 = 0
        static var crate:       UInt8 = 0
    }

    var displayed: Bool? {
        get {
            return getAssociatedObject(self, associativeKey: &AssociatedKey.displayed)
        }

        set {
            if let value = newValue {
                setAssociatedObject(self, value: value, associativeKey: &AssociatedKey.displayed, policy: objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            }
        }
    }

    var box: Box {
        get {
            if let result:Box = getAssociatedObject(self, associativeKey: &AssociatedKey.box) {
                return result
            } else {
                let result = Box(name: "")
                self.box = result
                return result
            }
        }

        set {
            setAssociatedObject(self, value: newValue, associativeKey: &AssociatedKey.box, policy: objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }

    var crate: Crate {
        get {
            if let result:Crate = getAssociatedObject(self, associativeKey: &AssociatedKey.crate) {
                return result
            } else {
                let result = Crate(name: "")
                self.crate = result
                return result
            }
        }

        set {
            setAssociatedObject(self, value: newValue, associativeKey: &AssociatedKey.crate, policy: objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}

새 저장소로 범주(Swift 확장)를 정의할 수 없습니다. 추가 속성은 저장하는 대신 계산해야 합니다.구문은 목적 C에 대해 작동합니다.@property범주에서 기본적으로 "제가 더 나은 사람과 더 나은 사람을 제공하겠습니다"를 의미합니다.Swift에서는 다음과 같은 계산된 속성을 얻으려면 이러한 속성을 직접 정의해야 합니다.

extension String {
    public var Foo : String {
        get
        {
            return "Foo"
        }

        set
        {
            // What do you want to do here?
        }
    }
}

잘 될 거예요.새 값은 세터에 저장할 수 없으며 기존의 사용 가능한 클래스 상태로만 작업할 수 있습니다.

0.02달러입니다.이 코드는 Swift 2.0으로 작성되었습니다.

extension CALayer {
    private struct AssociatedKeys {
        static var shapeLayer:CAShapeLayer?
    }

    var shapeLayer: CAShapeLayer? {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.shapeLayer) as? CAShapeLayer
        }
        set {
            if let newValue = newValue {
                objc_setAssociatedObject(self, &AssociatedKeys.shapeLayer, newValue as CAShapeLayer?, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            }
        }
    }
}

저는 많은 해결책을 시도해 보았는데, 이것이 추가 변수 매개 변수가 있는 클래스를 실제로 확장할 수 있는 유일한 방법이라는 것을 발견했습니다.

왜 objc 런타임에 의존합니까?저는 요점을 못 잡았어요.다음과 같은 방법을 사용하면 순수 Swift 접근 방식만 사용하여 저장된 속성과 거의 동일한 동작을 수행할 수 있습니다.

extension UIViewController {
    private static var _myComputedProperty = [String:Bool]()

    var myComputedProperty:Bool {
        get {
            let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self))
            return UIViewController._myComputedProperty[tmpAddress] ?? false
        }
        set(newValue) {
            let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self))
            UIViewController._myComputedProperty[tmpAddress] = newValue
        }
    }
}

저는 목표-C 유산에 의존하지 않고 순수한 스위프트에서 코드를 수행하는 것을 선호합니다.이 때문에 저는 두 가지 장점과 두 가지 단점을 가진 순수한 스위프트 솔루션을 작성했습니다.

장점:

  1. 퓨어 스위프트 코드

  2. 하거나 더 으로는 래스및작또보구로으체적다는클업완료▁and로▁on▁works으▁classes▁more에 대해 작업합니다.Any

단점:

  1. 코드가 메서드를 호출해야 합니다.willDeinit()하기 위해 특정 합니다.

  2. 할 수 . 왜냐하면 UIView는 UIView이기 때문입니다.var frame클래스의 일부가 아닌 UIView의 확장입니다.

편집:

import UIKit

var extensionPropertyStorage: [NSObject: [String: Any]] = [:]

var didSetFrame_ = "didSetFrame"

extension UILabel {

    override public var frame: CGRect {

        get {
            return didSetFrame ?? CGRectNull
        }

        set {
            didSetFrame = newValue
        }
    }

    var didSetFrame: CGRect? {

        get {
            return extensionPropertyStorage[self]?[didSetFrame_] as? CGRect
        }

        set {
            var selfDictionary = extensionPropertyStorage[self] ?? [String: Any]()

            selfDictionary[didSetFrame_] = newValue

            extensionPropertyStorage[self] = selfDictionary
        }
    }

    func willDeinit() {
        extensionPropertyStorage[self] = nil
    }
}

Obj-c 범주를 사용하면 인스턴스(instance) 변수가 아니라 메서드만 추가할 수 있습니다.

이 예제에서는 getter 및 setter 메서드 선언을 추가하기 위한 바로 가기로 @property를 사용했습니다.여전히 이러한 방법을 구현해야 합니다.

마찬가지로 Swift에서도 확장자를 사용하여 인스턴스 메서드, 계산된 속성 등을 추가할 수 있지만 저장된 속성은 추가할 수 없습니다.

주의: 추가 분석 후 아래 코드는 정상적으로 작동하지만 뷰 객체를 해제하지 않으므로, 방법을 찾을 수 있다면 답변을 수정하겠습니다. 그 동안 댓글을 읽어주세요.

이렇게 확장된 클래스에 정적 맵을 저장하는 것은 어떻습니까?

extension UIView {
    
    struct Holder {
        static var _padding:[UIView:UIEdgeInsets] = [:]
    }
   
    var padding : UIEdgeInsets {
        get{ return UIView.Holder._padding[self] ?? .zero}
        set { UIView.Holder._padding[self] = newValue }
    }

}

EXC_BAD_ACCESS 파일입니다.objc_getAssociatedObject()그리고.objc_setAssociatedObject()개체여야 합니다. 리고그.objc_AssociationPolicy개체와 일치해야 합니다.

여기에 나와 있는 몇 가지 답변에서 언급한 것처럼 objc_set Associated Object를 사용하려고 했지만 몇 번 실패한 후에 한 발 물러섰고 필요한 이유가 없다는 것을 깨달았습니다.여기 있는 아이디어 중 몇 가지를 빌려 추가 데이터(이 예에서는 MyClass)를 연결하고 싶은 객체에 의해 인덱싱된 배열을 저장하는 이 코드를 고안했습니다.

class MyClass {
    var a = 1
    init(a: Int)
    {
        self.a = a
    }
}

extension UIView
{
    static var extraData = [UIView: MyClass]()

    var myClassData: MyClass? {
        get {
            return UIView.extraData[self]
        }
        set(value) {
            UIView.extraData[self] = value
        }
    }
}

// Test Code: (Ran in a Swift Playground)
var view1 = UIView()
var view2 = UIView()

view1.myClassData = MyClass(a: 1)
view2.myClassData = MyClass(a: 2)
print(view1.myClassData?.a)
print(view2.myClassData?.a)

여기에 단순화되고 보다 표현력 있는 솔루션이 있습니다.값 유형과 참조 유형 모두에 대해 작동합니다.리프팅의 접근법은 @HepaKKES 답변에서 취합니다.

연결 코드:

import ObjectiveC

final class Lifted<T> {
    let value: T
    init(_ x: T) {
        value = x
    }
}

private func lift<T>(_ x: T) -> Lifted<T>  {
    return Lifted(x)
}

func associated<T>(to base: AnyObject,
                key: UnsafePointer<UInt8>,
                policy: objc_AssociationPolicy = .OBJC_ASSOCIATION_RETAIN,
                initialiser: () -> T) -> T {
    if let v = objc_getAssociatedObject(base, key) as? T {
        return v
    }

    if let v = objc_getAssociatedObject(base, key) as? Lifted<T> {
        return v.value
    }

    let lifted = Lifted(initialiser())
    objc_setAssociatedObject(base, key, lifted, policy)
    return lifted.value
}

func associate<T>(to base: AnyObject, key: UnsafePointer<UInt8>, value: T, policy: objc_AssociationPolicy = .OBJC_ASSOCIATION_RETAIN) {
    if let v: AnyObject = value as AnyObject? {
        objc_setAssociatedObject(base, key, v, policy)
    }
    else {
        objc_setAssociatedObject(base, key, lift(value), policy)
    }
}

사용 예:

확장을 만들고 확장에 속성을 연결합니다.값 속성과 참조 유형 속성을 모두 사용합니다.

extension UIButton {

    struct Keys {
        static fileprivate var color: UInt8 = 0
        static fileprivate var index: UInt8 = 0
    }

    var color: UIColor {
        get {
            return associated(to: self, key: &Keys.color) { .green }
        }
        set {
            associate(to: self, key: &Keys.color, value: newValue)
        }
    }

    var index: Int {
        get {
            return associated(to: self, key: &Keys.index) { -1 }
        }
        set {
            associate(to: self, key: &Keys.index, value: newValue)
        }
    }

}

이제 일반 속성으로 사용할 수 있습니다.

    let button = UIButton()
    print(button.color) // UIExtendedSRGBColorSpace 0 1 0 1 == green
    button.color = .black
    print(button.color) // UIExtendedGrayColorSpace 0 1 == black

    print(button.index) // -1
    button.index = 3
    print(button.index) // 3

자세한 정보:

  1. 포장 값 유형에는 리프팅이 필요합니다.
  2. 연결된 기본 개체 동작은 유지됩니다.연결된 개체에 대해 자세히 알고 싶다면문서를 확인하는 것이 좋습니다.

PURE SWIFT에서 기준 취급이 약한 경우

import Foundation
import UIKit

extension CustomView {
    
    // can make private
    static let storedProperties = WeakDictionary<UIView, Properties>()
    
    struct Properties {
        var url: String = ""
        var status = false
        var desc: String { "url: \(url), status: \(status)" }
    }
    
    var properties: Properties {
        get {
            return CustomView.storedProperties.get(forKey: self) ?? Properties()
        }
        set {
            CustomView.storedProperties.set(forKey: self, object: newValue)
        }
    }
}

var view: CustomView? = CustomView()
print("1 print", view?.properties.desc ?? "nil")
view?.properties.url = "abc"
view?.properties.status = true
print("2 print", view?.properties.desc ?? "nil")
view = nil

약한 사전.swift

import Foundation

private class WeakHolder<T: AnyObject>: Hashable {
    weak var object: T?
    let hash: Int

    init(object: T) {
        self.object = object
        hash = ObjectIdentifier(object).hashValue
    }

    func hash(into hasher: inout Hasher) {
        hasher.combine(hash)
    }

    static func ==(lhs: WeakHolder, rhs: WeakHolder) -> Bool {
        return lhs.hash == rhs.hash
    }
}

class WeakDictionary<T1: AnyObject, T2> {
    private var dictionary = [WeakHolder<T1>: T2]()

    func set(forKey: T1, object: T2?) {
        dictionary[WeakHolder(object: forKey)] = object
    }

    func get(forKey: T1) -> T2? {
        let obj = dictionary[WeakHolder(object: forKey)]
        return obj
    }

    func forEach(_ handler: ((key: T1, value: T2)) -> Void) {
        dictionary.forEach {
            if let object = $0.key.object, let value = dictionary[$0.key] {
                handler((object, value))
            }
        }
    }
    
    func clean() {
        var removeList = [WeakHolder<T1>]()
        dictionary.forEach {
            if $0.key.object == nil {
                removeList.append($0.key)
            }
        }
        removeList.forEach {
            dictionary[$0] = nil
        }
    }
}

Swift 3 및 Swift 4에 대해 Objective-C 관련 개체 및 계산된 속성을 사용하는 다른 예

import CoreLocation

extension CLLocation {

    private struct AssociatedKeys {
        static var originAddress = "originAddress"
        static var destinationAddress = "destinationAddress"
    }

    var originAddress: String? {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.originAddress) as? String
        }
        set {
            if let newValue = newValue {
                objc_setAssociatedObject(
                    self,
                    &AssociatedKeys.originAddress,
                    newValue as NSString?,
                    .OBJC_ASSOCIATION_RETAIN_NONATOMIC
                )
            }
        }
    }

    var destinationAddress: String? {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.destinationAddress) as? String
        }
        set {
            if let newValue = newValue {
                objc_setAssociatedObject(
                    self,
                    &AssociatedKeys.destinationAddress,
                    newValue as NSString?,
                    .OBJC_ASSOCIATION_RETAIN_NONATOMIC
                )
            }
        }
    }

}

UIView에 사용자 지정 문자열 속성을 설정하려는 경우 Swift 4에서 이렇게 했습니다.

UIView 확장 생성

extension UIView {

    func setStringValue(value: String, key: String) {
        layer.setValue(value, forKey: key)
    }

    func stringValueFor(key: String) -> String? {
        return layer.value(forKey: key) as? String
    }
}

이 확장자를 사용하려면

let key = "COLOR"

let redView = UIView() 

// To set
redView.setStringAttribute(value: "Red", key: key)

// To read
print(redView.stringValueFor(key: key)) // Optional("Red")

첫째, Associated Objects는 확장된 저장 속성에 가장 적합한 솔루션이어야 합니다. 이 솔루션은 Objective-C 런타임에서 제공되므로 Swift 언어의 다른 기본 기능이 있기 전에 사용해야 하는 강력한 기능입니다.

연결된 개체는 항상 신속한 개체를 포함하여 유지할 다른 개체가 없는 후에 해제되므로 사용자 지정 컨테이너를 사용하여 자동으로 해제되지 않는 대상 값을 유지하지 마십시오.

둘째, 관련된 추가적인 핵심 구조 정의의 경우, 핵심 기능은 다음과 같습니다.UnsafeRawPointer그것을 위해, 사실 그것을 위한 다른 최선의 선택이 있습니다.#function는 소스 코드를 컴파일할 때 생성되는 정적 문자열이며 사용할 자체 주소도 가지고 있습니다.

자, 여기 있습니다.

var status: Bool? {
    get { objc_getAssociatedObject(self, #function) as? Bool }
    set { objc_setAssociatedObject(self, #function, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)}
}

신속한 5를 위해 구축합니다.

마지막으로 연결 정책과 함께 개체 유형에 유의해야 합니다.

저는 objc_getAssociatedObject,objc_setAssociatedObject를 사용하여 속성을 저장하려고 했지만 실패했습니다.제 목표는 텍스트 입력 문자 길이를 확인하기 위해 UITextField의 확장자를 만드는 것이었습니다.다음 코드는 저에게 잘 맞습니다.이것이 누군가에게 도움이 되기를 바랍니다.

private var _min: Int?
private var _max: Int?

extension UITextField {    
    @IBInspectable var minLength: Int {
        get {
            return _min ?? 0
        }
        set {
            _min = newValue
        }
    }

    @IBInspectable var maxLength: Int {
        get {
            return _max ?? 1000
        }
        set {
            _max = newValue
        }
    }

    func validation() -> (valid: Bool, error: String) {
        var valid: Bool = true
        var error: String = ""
        guard let text = self.text else { return (true, "") }

        if text.characters.count < minLength {
            valid = false
            error = "Textfield should contain at least \(minLength) characters"
        }

        if text.characters.count > maxLength {
            valid = false
            error = "Textfield should not contain more then \(maxLength) characters"
        }

        if (text.characters.count < minLength) && (text.characters.count > maxLength) {
            valid = false
            error = "Textfield should contain at least \(minLength) characters\n"
            error = "Textfield should not contain more then \(maxLength) characters"
        }

        return (valid, error)
    }
}

다른 솔루션들은 작은 필요에서 벗어나 있습니다.

private var optionalID: String {
    UUID().uuidString
}

여기에도 효과적인 대안이 있습니다.

public final class Storage : AnyObject {

    var object:Any?

    public init(_ object:Any) {
        self.object = object
    }
}

extension Date {

    private static let associationMap = NSMapTable<NSString, AnyObject>()
    private struct Keys {
        static var Locale:NSString = "locale"
    }

    public var locale:Locale? {
        get {

            if let storage = Date.associationMap.object(forKey: Keys.Locale) {
                return (storage as! Storage).object as? Locale
            }
            return nil
        }
        set {
            if newValue != nil {
                Date.associationMap.setObject(Storage(newValue), forKey: Keys.Locale)
            }
        }
    }
}



var date = Date()
date.locale = Locale(identifier: "pt_BR")
print( date.locale )

저는 이 솔루션이 더 실용적이라고 생각했습니다.

Swift 3용으로 업데이트됨

extension UIColor {

    static let graySpace = UIColor.init(red: 50/255, green: 50/255, blue: 50/255, alpha: 1.0)
    static let redBlood = UIColor.init(red: 102/255, green: 0/255, blue: 0/255, alpha: 1.0)
    static let redOrange = UIColor.init(red: 204/255, green: 17/255, blue: 0/255, alpha: 1.0)

    func alpha(value : CGFloat) -> UIColor {
        var r = CGFloat(0), g = CGFloat(0), b = CGFloat(0), a = CGFloat(0)
        self.getRed(&r, green: &g, blue: &b, alpha: &a)
        return UIColor(red: r, green: g, blue: b, alpha: value)
    }

}

...그러면 당신의 코드로

class gameController: UIViewController {

    @IBOutlet var game: gameClass!

    override func viewDidLoad() {
        self.view.backgroundColor = UIColor.graySpace

    }
}

언급URL : https://stackoverflow.com/questions/25426780/how-to-have-stored-properties-in-swift-the-same-way-i-had-on-objective-c

반응형