Difference between weak self vs weak self() - ios

What is the difference between passing [weak self] as an argument to a closure vs passing [weak self] ()
For example :
dispatch_async(dispatch_get_main_queue()) { [weak self] in
//Some code here
}
v/s
dispatch_async(dispatch_get_main_queue()) { [weak self] () -> Void in
//Some code here
}

You do not pass [weak self] () as an argument to a closure.
[weak self] is a capture list and precedes the
parameter list/return type declaration () -> Void
in the closure expression.
The return type or both parameter list and return type can be omitted if they can
be inferred from the context, so all these are valid
and fully equivalent:
dispatch_async(dispatch_get_main_queue()) { [weak self] () -> Void in
self?.doSomething()
}
dispatch_async(dispatch_get_main_queue()) { [weak self] () in
self?.doSomething()
}
dispatch_async(dispatch_get_main_queue()) { [weak self] in
self?.doSomething()
}
The closure takes an empty parameter list () and has a Void
return type.

Related

Is 2nd [weak self] ever required in a closure inside another closure?

I always like to use [weak self], to prevent any potential memory leakage.
I was wondering, is 2nd [weak self] required, in a closure inside another closure? For instance
2 [weak self]
func takePhoto() {
AVCaptureDevice.requestAccess(for: AVMediaType.video) { [weak self] response in
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
Or, it is redundant to do so for the above case, and single [weak self] will be sufficient?
Single [weak self]
func takePhoto() {
AVCaptureDevice.requestAccess(for: AVMediaType.video) { [weak self] response in
DispatchQueue.main.async {
guard let self = self else { return }
May I know, which one is the most accurate approach?

want to set a self var using guard statement

I have this code, where I'm trying to set a self variable (self?.users) from a view model call. The code snippet looks like this.
override func viewWillAppear(_ animated: Bool) {
DispatchQueue.global().async { [weak self] in
self?.model?.findAll() { [weak self] users, exception in // network call
guard users != nil, self?.users = users else { // Optional type ()? cannot be used as a boolean; test for !=nil instead
}
}
DispatchQueue.main.async {
self?.tableView.reloadData()
}
}
}
I'm capturing [weak self] twice, is that okay?, can I capture it once as weak in the enclosing closure?
Should I use this instead of guard statement?
self?.model?.findAll() { [weak self] users, exception in
if exception != nil {
self?.users = users
}
}
DispatchQueue closures don't cause retain cycles so capture lists are not necessary.
Something like this, to avoid confusion I'd recommend to rename the incoming users and the code to reload the table view must be inside the closure
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
DispatchQueue.global().async {
self.model?.findAll() { [weak self] foundUsers, exception in // network call
guard let foundUsers = foundUsers else { return }
self?.users = foundUsers
DispatchQueue.main.async {
self?.tableView.reloadData()
}
}
}
}
And don’t forget to call super

Correct memory management in closures

I have method with closure.
It works like this
func ping() -> pingProtocol {
let factory = pingFactory()
let ping = factory.getPing() // returns pingProtocol conforming instance, for example "PingService"
return ping
}
func performPing(success: #escaping () -> (), fail: #escaping () -> ()) {
ping().status { (ready, response) in
if ready {
success()
} else {
fail()
}
}
}
Realisation of ping is abstraction over Alamofire.
class PingService {
func status(completion: #escaping (Bool, ServiceResponse) -> Void) {
doSimpleRequest(endPoint: "/api/get_state/", param: [:], completion: completion)
}
func doSimpleRequest(endPoint: String, param: [String: Any], completion: #escaping (Bool, ServiceResponse) -> Void) {
APIManager.shared.postRequest(mode: APIMode.Service, endPoint: endPoint, parameters: param) { [weak self] (response, error) in
guard let strongSelf = self else {
return
}
guard let response = response as? [String: Any] else { return }
let serviceResponse = ServiceResponse(dict: response)
if error != nil {
completion(false, serviceResponse)
return
}
completion(true, serviceResponse)
}
}
}
The problem is that with weak self guard in self is always triggers. If I use unowned, I get crash. If I dont use weak or unowned it works fine.
The ping method itself lives in viewmodel of controller, and controller stays on screen when completion block is needed to be executed, so the problem is in deallocation of ping instance, not in viewmodel thats holds it.
If I use capture list I dont get desired behavior, but If I do I suspect that I get memory leak.
What is best practice here ?

DispatchGroup returning multiple times

Below code which I am using to make concurrent API call. somehow this method returning multiple times. I have tested without DispatchGroup, It is working as expected. Help me to find why it is calling multiple times.
My Code Snippet :
func makeConcurrentCallForUpdating(_ parent: Parent,
completionBlock: #escaping (_ success: Bool, _ error: DescriptiveErrorType?) -> Void)
let fetchGroup = DispatchGroup()
let queue = DispatchQueue.global(qos: .default)
let endPoints = [.email, .others ]
DispatchQueue.concurrentPerform(iterations: endPoints.count) { (index) in
let enumType = endPoints[index]
switch enumType {
case .email:
updateEmail(parent, fetchGroup: fetchGroup, completionBlock: completionBlock)
case .others:
update(parent, fetchGroup: fetchGroup, completionBlock: completionBlock)
default:
break
}
}
fetchGroup.notify(queue: queue) {
if self.endPoints.count > 0 {
completionBlock(false, error)
} else {
self.saveUpdated(parent, completionBlock: completionBlock)
}
}
}
#MARK: EMAIL CALL
fileprivate func updateEmail(_ parent: Parent,
fetchGroup: DispatchGroup,
completionBlock: #escaping (_ success: Bool, _ error: DescriptiveErrorType?) -> Void) {
fetchGroup.enter()
updateEmail(parent: parent) { (success, error) in
fetchGroup.leave()
}
}
You need to enter() all dispatched tasks before any task in the group will leave().
Move your fetchGroup.enter() before DispatchQueue.concurrentPerform(...
let endPoints = [.email, .others ]
endPoints.forEach {_ in fetchGroup.enter()} //<- add this line
DispatchQueue.concurrentPerform(iterations: endPoints.count) { (index) in
And remove fetchGroup.enter() in each task:
fileprivate func updateEmail(_ parent: Parent,
fetchGroup: DispatchGroup,
completionBlock: #escaping (_ success: Bool, _ error: DescriptiveErrorType?) -> Void) {
//fetchGroup.enter() //<- remove this line, in your `update(...)` as well
updateEmail(parent: parent) { (success, error) in
fetchGroup.leave()
}
}
Please try.

Write UIView animation function that animates a view specific times

How to refactore code to be more compact by sending the function the view , number of animated times , applied action function and success funtion
If functional programming solution can be proposed it will be helpful
typealias AnimateAction = UIView -> Void
typealias AnimateSuccess = Bool -> Void
func animateThreetimes(animatedView:UIView,animateAction:AnimateAction,animateSuccess:AnimateSuccess)
{
UIView.animateWithDuration(0.5, animations: { () -> Void in
animateAction(animatedView)
}) { (success) -> Void in
UIView.animateWithDuration(1, animations: { () -> Void in
animateAction(animatedView)
}, completion: { (success) -> Void in
UIView.animateWithDuration(0.5, animations: { () -> Void in
animateAction(animatedView)
}, completion: { (success) -> Void in
animateSuccess(success)
})
})
}
}
Recursion would do quite nicely:
func animate(count: Int) {
if count > 0 {
UIView.animateWithDuration(0.2, animations: { () -> Void in
// do the animations
}, completion: { (_) -> Void in
self.animate(count-1);
})
}
}
You could also do something like this to have a bit more control of the variables you are passing in and how you want to handle the completion. Furthermore this answers your request for a functional solution to the problem.
typealias AnimationAction = UIView -> Void
typealias AnimationSuccess = Bool -> Void
func animateView(view: UIView, animationAction: AnimationAction) -> (duration: NSTimeInterval, completionHandler: AnimationSuccess?) -> Void {
// Return a function that takes a duration and a maybe completion handler
return { duration, completionHandler in
return UIView.animateWithDuration(duration, animations: {
animationAction(view)
}, completion: { finished in
completionHandler?(finished) // Optional function only called if exists
})
}
}
// Just showing the mechanism
let durations = [0.5, 1, 0.5]
for index in 0..<durations.count {
let view = UIView(frame: CGRectZero)
let animationAction: AnimationAction = { view in
print("View: \(view)")
}
let completionHandler: AnimationSuccess? = {
if durations[index] == durations.last {
return { finished in
print(finished)
}
} else {
return nil
}
}()
animateView(view, animationAction: animationAction)(duration: durations[index], completionHandler: completionHandler)
}
Assuming that you want a general approach that could be used for an arbitrary number of animations ...
You could include a counter variable in the function call, decrement it when you have animated, and while it is non-zero, call the animate function again

Resources