Using unowned reference in a closure - swift

The The Swift Programming Language documentation states:
Define a capture in a closure as an unowned reference when the closure and the instance it captures will always refer to each other, and will always be deallocated at the same time.
So the only scenario that come to my mind is this one:
class ClassWithClosure {
lazy var someClosure: () -> String = {
[unowned self] in
self.myMethod()
}
func myMethod(){
}
}
Are there more scenarios where the closure and the instance will be deallocated at the same time?

Anytime ClassWithClosure instance's reference count hits 0, the instance will be deallocated. Since the instance is getting deallocated, its properties would be deallocated as well. So anytime ClassWithClosure instance is deallocated, the closure would be deallocated as well. You can't tell the same for other way around. What I mean is if you set someClosure to nil, then it won't cause deallocation of the ClassWithClosure instance.

I'm late. Just now looking into these matters for myself. How about this?
protocol Notifier {
typealias Client = (Data) -> Void
typealias Token = Any
func register(client: Client) -> Token
// The previously registered Consumer is discarded
func deregister(token: Token)
}
class Registrant {
private let name: String
private let notifier: Notifier
private var token: Notifier.Token? = nil
init(name: String, notifier: Notifier) {
self.name = name
self.notifier = notifier
token = notifier.register { [unowned self] (data: Data) in
print("\(self.name) has been notified: \(data)")
}
}
deinit {
if let token = token {
notifier.deregister(token: token)
}
}
}

Related

Understanding Swift Closure Capturing

I have gone through Swift Closures and ARC in Swift and I got little confused.
I have simple scenario of calling web service and using response data.
Here is my basic implementation:
class WebServices: NSObject {
func requestDataFromServer(completion: #escaping (_ data: Data?) -> Void) {
//web service call here
completion(Data())
}
deinit {
print("WebServices deinitializer...")
}
}
class Controller: NSObject {
private let webService = WebServices()
private func useResponseData(_ data: Data) {
print("Response Data: \(data)")
}
func fetchData() {
webService.requestDataFromServer { (data) in
if let responseData = data {
self.useResponseData(responseData)//direct use of self
}
}
}
deinit {
print("Controller deinitializer...")
}
}
var controller: Controller? = Controller()
controller!.fetchData()
controller = nil
Console output is:
Response Data: 0 bytes
Controller deinitializer...
WebServices deinitializer...
My question is even I'm using selfdirectly inside closure why this implementation is not causing Reference Retain Cycle?
If I use unowned or weak then also same behavior.
And what can cause reference retain cycle in above scenario?(I don't want to cause, rather want to be aware of mistakes)
There is no issue in your code as requestDataFromServercall the completion handler directly (no async). So the caller can't have been released during you call.
But when you will implement your webservice's real call, it will be async. So user can switch page before your webservice answer. In that case, you will retain a strong reference to your controller and it will never be released. You should use a [weak self]in your closure (and so call self?.useResponseData(responseData) with self as optional).
unowned is used in case that you are sure your reference will not be nil (it's not an optional)
Ok, I guess the problem is what you are doing here is not actually async, so it executes one after another, this code causes memory leak:
import Foundation
class WebServices {
func requestDataFromServer(completion: #escaping (_ data: Data?) -> Void) {
//web service call here
print("called")
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: {
print("called async")
completion(Data())
})
}
deinit {
print("WebServices deinitializer...")
}
}
class Controller: UIViewController {
private let webService = WebServices()
private func useResponseData(_ data: Data) {
print("Response Data: \(data)")
}
func fetchData() {
webService.requestDataFromServer { (data) in
print("called")
if let responseData = data {
self.useResponseData(responseData)//direct use of self
}
}
self.dismiss(animated: true, completion: nil)
}
deinit {
print("Controller deinitializer...")
}
}
var controller: Controller? = Controller()
controller!.fetchData()

Save struct in background mutating function

I'm trying to save a struct in background but I get this error :
closure cannot implicitly capture a mutating self parameter
This is my code :
//MARK: Parse self methods
fileprivate mutating func ParseSave(_ completionBlock: #escaping SuccessCompletionBlock) {
let message: PFObject = PFObject(className: "Message")
if let id = self.id {
//this object exit just update it
message.objectId = id
}
// set attributes
if let text = self.text {
message["text"] = text
}
message["sender"] = PFUser(withoutDataWithObjectId: self.sender.id)
message["conversation"] = PFObject(withoutDataWithClassName: "Conversation", objectId: conversationId)
message["viewed"] = self.viewed
message.saveInBackground { (success, error) in
if success {
// the next 3 lines cause the error : (when I try to update the struct - self )
self.id = message.objectId
self.createdAt = message.createdAt ?? self.createdAt
self.updatedAt = message.updatedAt ?? self.updatedAt
}
completionBlock(success, error)
}
}
I've checked those question: 1 - 2 I've added the #escaping
but didn't work.
I think it will help if we minimally elicit the error message you're getting. (For delay, see dispatch_after - GCD in swift?.)
struct S {
var name = ""
mutating func test() {
delay(1) {
self.name = "Matt" // Error: Closure cannot ...
// ... implicitly capture a mutating self parameter
}
}
}
The reason lies in the peculiar nature of struct (and enum) mutation: namely, it doesn't really exist. When you set a property of a struct, what you're really doing is copying the struct instance and replacing it with another. That is why only a var-referenced struct instance can be mutated: the reference must be replaceable in order for the instance to be mutable.
Now we can see what's wrong with our code. Obviously it is legal for a mutating method to mutate self; that is what mutating means. But in this case we are offering to go away for a while and then suddenly reappear on the scene (after 1 second, in this case) and now mutate self. So we are going to maintain a copy of self until some disconnected moment in the future, when self will suddenly be somehow replaced. That is incoherent, not least because who knows how the original self may have been mutated in the meantime, rendering our copy imperfect; and the compiler prevents it.
The same issue does not arise with a nonescaping closure:
func f(_ f:()->()) {}
struct S {
var name = ""
mutating func test() {
f {
self.name = "Matt" // fine
}
}
}
That's because the closure is nonescaping; it is executed now, so the incoherency about what will happen in the future is absent. This is an important difference between escaping and nonescaping closures, and is one of the reasons why they are differentiated.
Also, the same issue does not arise with a class:
class C {
var name = ""
func test() {
delay(1) {
self.name = "Matt" // fine
}
}
}
That's because the class instance is captured by reference in the closure, and a class instance is mutable in place.
(See also my little essay here: https://stackoverflow.com/a/27366050/341994.)

NSNotification subclass with Generics in Swift 2.1

Can't make subclass of NSNotification with Generic payload object. Getting either runtime error or compile error (see comments in code below). Is it even possible with Swift 2.1? Any ideas appreciated. Thanks!
Runtime error because NSNotification is abstract class (class cluster).
Compile error because designated initializer should be used.
public class Notification<T: Any>: NSNotification {
private var _name: String
private var _object: AnyObject?
private var _payload: T?
public override var name: String {
return _name
}
public override var object: AnyObject? {
return _object
}
public var payload: T? {
return _payload
}
/// Always nil. Use payload
public override var userInfo: [NSObject : AnyObject]? {
return nil
}
/// Change to false to "swap" implementation
#if true
init(name: String, object: AnyObject? = nil, payload: T? = nil) {
_name = name
_object = object
_payload = payload
/*
Runtime error:
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason:
'*** initialization method -initWithName:object:userInfo:
cannot be sent to an abstract object of class
_TtGC14__lldb_expr_1612NotificationSS_:
Create a concrete instance!'
*/
super.init(name: name, object: object, userInfo: nil)
}
#else
convenience init(name: String, object: AnyObject? = nil, payload: T? = nil) {
self.init()
_name = name
_object = object
_payload = payload
}
init() {
/// compiler error:
/// must call a designated initializer of the superclass
/// But using designated initializer cause runtime error listed above.
super.init()
}
#endif
}
let n = Notification<String>(name: "xyz", payload: "Hello")
From the docs, emphasis mine:
You can subclass NSNotification to contain information in addition to the notification name, object, and dictionary. This extra data must be agreed upon between notifiers and observers.
NSNotification is a class cluster with no instance variables. As such, you must subclass NSNotification and override the primitive methods name, object, and userInfo. You can choose any designated initializer you like, but be sure that your initializer does not call [super init]. NSNotification is not meant to be instantiated directly, and its init method raises an exception.
There's no way subclass NSNotification from Swift code right now, as Swift has no concept of "uninitializable classes" and requires that all subclasses invoke their superclass's init (which, in this case, is the wrong thing to do).
You'll have to write the subclass in Objective-C and bridge it into your Swift code.
Unfortunately, even though you can declare your Objective-C class generic, that information is lost in the bridging process. From the docs:
Aside from these Foundation collection classes, Objective-C lightweight generics are ignored by Swift. Any other types using lightweight generics are imported into Swift as if they were unparameterized.
:(
I solved original problem without subclassing.
File GenericNotification.swift:
private let genericNotificationPayloadKey = "com.mc.notification-payload"
class GenericNotification<T: Any> {
let payload: T
let name: NSNotification.Name
let object: Any?
init(name: NSNotification.Name, object: Any? = nil, payload: T) {
self.name = name
self.object = object
self.payload = payload
}
init?(notification: Notification) {
guard let payload = notification.userInfo?[genericNotificationPayloadKey] as? T else {
return nil
}
self.payload = payload
name = notification.name
object = notification.object
}
}
extension GenericNotification {
var notification: Notification {
return Notification(name: name, object: object, userInfo: [genericNotificationPayloadKey: payload])
}
static func observe(name: NSNotification.Name,
object: Any? = nil,
queue: OperationQueue = .main,
handler: #escaping (T) -> Void) -> NotificationObserver {
return NotificationObserver(name: name, object: object, queue: queue) {
if let notification = GenericNotification(notification: $0) {
handler(notification.payload)
}
}
}
func post(center: NotificationCenter = NotificationCenter.default) {
center.post(notification)
}
}
File NotificationObserver.swift:
class NotificationObserver: NSObject {
typealias Handler = ((Foundation.Notification) -> Void)
private var notificationObserver: NSObjectProtocol!
var notificationHandler: Handler?
private let notificationName: NSNotification.Name
private let notificationObject: Any?
init(name: NSNotification.Name, object: Any? = nil, queue: OperationQueue = .main, handler: Handler? = nil) {
notificationName = name
notificationObject = object
notificationHandler = handler
super.init()
notificationObserver = NotificationCenter.default.addObserver(forName: name, object: object, queue: queue) { [weak self] in
self?.handleNotification($0)
}
}
deinit {
NotificationCenter.default.removeObserver(notificationObserver, name: notificationName, object: notificationObject)
}
/// Calls block which was passed as *usingBlock* parameter.
/// Child classes may override to change default behaviour.
/// - parameter notification: Notification to handle.
func handleNotification(_ notification: Foundation.Notification) {
notificationHandler?(notification)
}
}
Usage:
// Send notification
let action = MyType.doSomething
GenericNotification(name: .myNotificationName, payload: action).post()
// Receive notification
private var notificationObservers: [NotificationObserver] = []
...
notificationObservers.append(GenericNotification<MyType>.observe(name: .myNotificationName) { instanceOfMyType in
// Got `instanceOfMyType` which is `MyType.doSomething`
})

How to use instance method as callback for function which takes only func or literal closure

In "ViewController.swift" I am creating this callback:
func callback(cf:CFNotificationCenter!,
ump:UnsafeMutablePointer<Void>,
cfs:CFString!,
up:UnsafePointer<Void>,
cfd:CFDictionary!) -> Void {
}
Using this observer:
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
nil,
self.callback,
"myMESSage",
nil,
CFNotificationSuspensionBehavior.DeliverImmediately)
Results in this compiler error:
"A C function pointer can only be formed from a reference to a 'func' or a literal closure"
The callback is a pointer to a C function, and in Swift you can pass
only a global function or a closure (which does not capture any state),
but not an instance method.
So this does work:
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
nil,
{ (_, observer, name, _, _) in
print("received notification: \(name)")
},
"myMessage",
nil,
.DeliverImmediately)
But since the closure cannot capture context, you have no direct reference to self and its properties and instance methods.
For example, you cannot add
self.label.stringValue = "got it"
// error: a C function pointer cannot be formed from a closure that captures context
inside the closure to update the UI when a notification arrived.
There is a solution, but it is a little bit complicated due to
Swift's strict type system.
Similarly as in Swift 2 - UnsafeMutablePointer<Void> to object, you can convert the pointer to
self to a void pointer, pass that as the observer parameter
to the registration, and convert it back to an object pointer in
the callback.
class YourClass {
func callback(name : String) {
print("received notification: \(name)")
}
func registerObserver() {
// Void pointer to `self`:
let observer = UnsafePointer<Void>(Unmanaged.passUnretained(self).toOpaque())
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
observer,
{ (_, observer, name, _, _) -> Void in
// Extract pointer to `self` from void pointer:
let mySelf = Unmanaged<YourClass>.fromOpaque(
COpaquePointer(observer)).takeUnretainedValue()
// Call instance method:
mySelf.callback(name as String)
},
"myMessage",
nil,
.DeliverImmediately)
}
// ...
}
The closure acts as a "trampoline" to the instance method.
The pointer is an unretained reference, therefore you must ensure
that the observer is removed before the object is deallocated.
Update for Swift 3:
class YourClass {
func callback(_ name : String) {
print("received notification: \(name)")
}
func registerObserver() {
// Void pointer to `self`:
let observer = UnsafeRawPointer(Unmanaged.passUnretained(self).toOpaque())
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
observer,
{ (_, observer, name, _, _) -> Void in
if let observer = observer, let name = name {
// Extract pointer to `self` from void pointer:
let mySelf = Unmanaged<YourClass>.fromOpaque(observer).takeUnretainedValue()
// Call instance method:
mySelf.callback(name.rawValue as String)
}
},
"myMessage" as CFString,
nil,
.deliverImmediately)
}
// ...
}
See also How to cast self to UnsafeMutablePointer<Void> type in swift for more information
about the "bridging" between object pointers and C pointers.
In my case the function I wanted to call from my closure was in the AppDelegate. So I was able to use a delegate to call the function from the closure without using self. Whether this is a good idea or not is something that someone with more experience will have to comment on.
self.pingSocket = CFSocketCreate(kCFAllocatorDefault, AF_INET, SOCK_DGRAM, IPPROTO_ICMP,CFSocketCallBackType.dataCallBack.rawValue, {socket, type, address, data, info in
//type is CFSocketCallBackType
guard let socket = socket, let address = address, let data = data, let info = info else { return }
// stuff deleted, including use of C pointers
let appDelegate = NSApplication.shared.delegate as! AppDelegate
appDelegate.receivedPing(ip: sourceIP, sequence: sequence, id: id)
//}
return
}, &context)
extension AppDelegate: ReceivedPingDelegate {
func receivedPing(ip: UInt32, sequence: UInt16, id: UInt16) {
// stuff deleted
}
}
protocol ReceivedPingDelegate: class {
func receivedPing(ip: UInt32, sequence: UInt16, id: UInt16)
}

weak to non class types to avoid memory leak

I've got a memory leak in this case, if I pass a reference to any method, the self comes with it which increases it's reference count I guess, how can I make non class types to be weak
public class Observer {
weak private var method: ((message: AnyObject) -> ())! //error here
weak private var context: AnyObject!
}
public init(method: (AnyObject -> ())?, context: AnyObject?) {
self.method = method
self.context = context
}
in another class I guess self.callback creates a strong reference to the caller object and passes on.
var observer = Observer(method: self.callback, context: self) //pass of self.callback is a strong reference
Edit:
Working on the above, my attempt using an example that further clarifies the situation using two classes. deinit never gets called.
class Test {
private var ref: Observer?
init() {
ref = Observer(method: self.callback, context: self)
}
func callback(message: AnyObject) {
}
deinit {
println("deinit test")
}
}
public class Observer {
private var method: ((message: AnyObject) -> ())?
weak private var context: AnyObject!
public init(method: (AnyObject -> ())?, context: AnyObject?) {
self.method = method
self.context = context
}
deinit {
println("deinit observer")
}
}
From looking at your code, it seems like you are talking about a retain cycle where the Test object holds onto the Observer object through the variable ref, the Observer object holds onto the closure formed by doing self.callback, which holds onto self.
Generally in such cases, you don't want the closure property itself to be weak. Rather, you want the closure to capture a weak reference to self (the Test object is passing a "callback" to itself to another object). However, that is somewhat confusing here as we are not explicitly using closure syntax (rather, you are getting a closure by accessing a method on an instance and not calling it). The problem of capturing a weak reference to self in this case was covered in this question.
The best solution is:
ref = Observer(method: {[unowned self] in self.callback($0)}, context: self)
Try this:
public class Observer {
private var method: ((message: AnyObject) -> ())?
weak private var context: AnyObject!
public init(method: (AnyObject -> ())?, context: AnyObject?) {
self.method = method
self.context = context
}
}
I tried it and it doesn't create a strong reference cycle. But I also tried with ! instead of ?, and that didn't caused as well, and I hope somebody is out there to explain that.