0

Following code works but I was forced by the compiler to use self inside dispatch_sync, IMO I believe self isn't created yet and shouldn't be accessible. why self inside a static function?

I was trying to use this way instead

        dispatch_sync(queue, {
            if (object == nil) {
                object = SingleObject()
            }
        })
        return object!

working version

import Foundation

public class SingleObject {

    public struct Static {

        private static var object: SingleObject?

        public static func getObject() -> SingleObject {
            let queue = dispatch_queue_create("queue", nil)

            dispatch_sync(queue, {
                if (self.object == nil) {
                    self.object = SingleObject()
                }
            })
            return object!
        }
    }

}

SingleObject.Static.getObject()
user2727195
  • 7,122
  • 17
  • 70
  • 118

1 Answers1

0

The problem is not about dispatch_async, but it's because you are referencing self in a closure.

Whenever self is used in a closure, it is captured as a strong reference. That can potentially cause a strong reference cycle - to prevent that self is captured by mistake, swift requires that self is explicitly used when accessing properties and methods.

Note that self is defined in a static context, and refers to the type rather than an instance. So using self in a static method lets you access all static properties and methods defined in the same class/struct.

For more info, read Automatic Reference Counting

Antonio
  • 71,651
  • 11
  • 148
  • 165
  • is there going to be a memory leak problem using this way? apart from the question do you think it's the a better way to create single objects, it differs from the other examples since getObject is part of struct itself, in other examples they'd access the struct from outside the struct but within the class, I just nested that functionality within the struct (Encapsulation) – user2727195 Dec 30 '14 at 23:40
  • when 2 objects have a strong reference to each other, then yes, because one will wait for the other to be released. This condition is explained in the documentation I linked in the answer, so I highly recommend to read it. – Antonio Dec 30 '14 at 23:46
  • I'll read as it's gonna take some time, but any suggestions to make it memory leak free, will this work or please advise. `if (Static.object == nil) { Static.object = SingleObject() }` – user2727195 Dec 30 '14 at 23:50
  • However if what you are implementing is the singleton pattern, then I suggest you to look at [this answer](http://stackoverflow.com/a/24073016/148357), there is a better and shorter way to achieve that. – Antonio Dec 30 '14 at 23:50
  • great example, any suggestions for multitons – user2727195 Dec 31 '14 at 00:00
  • No, sorry. Never used - the most obvious way I can think of is a singleton dictionary, but probably there are better ways of doing it. – Antonio Dec 31 '14 at 08:56
  • in case it's a static singleton dictionary, so it will be pre-instantiated, i.e. no initialized both lazy and wrapped in dispatch_once will benefit in this case (as per the info on the link) meaning have to manually take care of dispatch queues/sync while accessing instance for each dictionary key, correct? – user2727195 Dec 31 '14 at 10:40
  • Yes, seems correct. In that case it's probably better to wrap the dictionary in a class/struct, put all sync logic there, and expose just the methods you want to be accessible – Antonio Dec 31 '14 at 10:43
  • I read the apple article on ARC, one more confirmation in context of multitons, if I'm using self inside dispatch closure, I'll add `[unowned self]` before param list to avoid reference cycle, but what if I create the dictionary as `Static.instances`, where `Static` is an inner structure (inside class) and `instances` is a dictionary, I don't have to worry about cyclic references, because I'm accessing a struct from a closure, right? – user2727195 Dec 31 '14 at 12:34
  • More generally I think that in this case I don't see any risk of reference cycle because you don't have 2 classes each storing a reference to the other - there's just one class – Antonio Dec 31 '14 at 12:41
  • Hi Antonio, one more question, since you know the context, if for some reason I do want to capture self inside the block, because I'm afraid that caller of the block (the class itself) will go out of scope, in that case I let it capture, and when the block is called and just before it returns, i should set `self = nil`, but I can't assign nil to self in there, some more context, it's async pattern, the class or command is created, temporarily, passes a block of code, it itself gets out of scope, and then the blocks gets called asynchronously later with reference to self, any strategy – user2727195 Jan 04 '15 at 22:47
  • You should define the reference to self as unowned if you want to be sure that self is still valid - and you don't have to do anything to release it, because it's automatically done. In swift you cannot assign a value to self – Antonio Jan 04 '15 at 23:04
  • okay, that resolves the concern, so self gets released automatically once the block ends, i.e. no memory leak, so I'll put the [unowned self] back. please correct me if I'm wrong. Thanks – user2727195 Jan 04 '15 at 23:06