2

In Objective-C I often use the pattern of using a static void* as an identification tag. At times these tags are only used within that function/method, hence it's convenient to place the variable inside the function.

For example:

MyObscureObject* GetSomeObscureProperty(id obj) {
    static void* const ObscurePropertyTag = &ObscurePropertyTag;
    MyObscureObject* propValue = objc_getAssociatedObject(id,ObscurePropertyTag);
    if(!propValue) {
        propValue = ... // lazy-instantiate property
        objc_setAssociatedObject(obj,ObscurePropertyTag,propValue, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
    return propValue; 
}

The question is, how to write the ObscurePropertyTag private-constant-pointer-to-itself in Swift? (Preferrably 2.1 but future already-announced versions should be okay)

I've looked around and it seems that I have to put this ObscurePropertyTag as a member variable and there doesn't seem to be a way around it.

adib
  • 8,285
  • 6
  • 52
  • 91
  • Can you elaborate on what you're trying to achieve. Converting your Objective-C code to the Swift equivalent may not be the best option. – Michael Feb 11 '16 at 04:19
  • @Michael One example is to associate `MKPolyline` objects shown within a map view with their underlying data model objects. Another is for identifying particular subsets of `CALayer` objects (without creating yet another collection object to contain them). – adib Feb 11 '16 at 05:39

2 Answers2

4

Unlike (Objective-)C, you cannot take the address of an uninitialized variable in Swift. Therefore creating a self-referencing pointer is a two-step process:

Swift 2:

var ptr : UnsafePointer<Void> = nil
withUnsafeMutablePointer(&ptr) { $0.memory = UnsafePointer($0) }

Swift 3:

var ptr = UnsafeRawPointer(bitPattern: 1)!
ptr = withUnsafePointer(to: &ptr) { UnsafeRawPointer($0) }

For your purpose, is it easier to use the address of a global variable with &, see for example

If you want to restrict the scope of the "tag" to the function itself then you can use a static variable inside a local struct. Example:

func obscureProperty(obj : AnyObject) -> MyObscureObject {
    struct Tag {
        static var ObscurePropertyTag : Int = 0
    } 
    if let propValue = objc_getAssociatedObject(obj, &Tag.ObscurePropertyTag) as? MyObscureObject {
        return propValue
    }
    let propValue = ... // lazy instantiate property value
    objc_setAssociatedObject(obj, &Tag.ObscurePropertyTag,propValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    return propValue
}
Community
  • 1
  • 1
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
0

Try this:

var GetSomeObscureProperty: MyObscureObject = nil

withUnsafePointer(& GetSomeObscureProperty) {
    GetSomeObscureProperty = MyObscureObject($0) 
}

In short

let GetSomeObscureProperty = UnsafePointer<()>()
TechBee
  • 1,897
  • 4
  • 22
  • 46