最新消息:20210917 已从crifan.com换到crifan.org

【已解决】Alamofire返回的response中weak self的含义和是否可以去掉

iOS crifan 2097浏览 0评论

在看别人写的代码时,用到了http网络的库:Alamofire

func getUrlRespJson_async(httpMethod:Alamofire.HTTPMethod,
                          url:String,
                          parameters: [String : AnyObject]? = nil,
                          headers:[String:String]? = nil,
                          requsetType: SRTRequsetType = .json,
                          respJsonHandle:@escaping (_ httpResult: SRTHttpResult)-> Void) {
    let curHttpReq = Alamofire.request(url, method: httpMethod, parameters: parameters, encoding: paramEncoding, headers: curHeaders)
}
getUrlRespJson_async(
    httpMethod: .get,
    url: url,
    parameters: nil,
    respJsonHandle: { [weak self] (response) in
        dispatchMain_async({
            self?.endRefresh()
            self?.clearAllNotice()
        })
        self?.getTasksCount()
        

其中用到了weak self

但是我之前好像没用过weak self,貌似也是可以的。

所以此处要去搞清楚,

weak self的含义

是否可以去掉weak self -》 否则self?写起来也挺麻烦的。

Alamofire response weak self

ios – Swift weakSelf in closure syntax – Stack Overflow

说是写成: [unowned self]

Demystifying Retain Cycles in ARC – Digital Leaves

The Swift Programming Language (Swift 4): Automatic Reference Counting

官网中有weak和unowned的解释

ios – Do I need [unowned self] in AlamoFire, or is it already taken care of? – Stack Overflow

说是:如果不清楚,就用weak self,反正没坏处,但是如果不用,在涉及self.alamoFireManager时,alamoFireManager本身是属于self的,则会导致一个循环引用(retain cycle)

ios – Swift weakSelf in closure syntax – Stack Overflow

responseString method is incorrectly saying success · Issue #1205 · Alamofire/Alamofire · GitHub

Alamofire 使用指南 – 简书

目前感觉像是:

由于http网络调用是异步的,等网络返回后,之前的self,对应着当前的类的实例,可能都已经被销毁了,可能不存在了,所以此处的self,不应该是强引用,否则self.xxx,就直接报错,app就挂了。

即使都用weak self,也可以用更好的方式,避免self?的写法:

[weak self]
guard let strongSelf = self else { return }

ARC是通过引用计数实现的。

引用计数,只适用于类的实例。

结构体和枚举是没有ARC的。

strong reference cycle=强引用循环=循环引用=retain cycle

alamofire weak self

Alamofire 4.0.0 memory leaks with uploadProgress and downloadProgress · Issue #1551 · Alamofire/Alamofire · GitHub

Alamofire 4 FAILURE: Error Domain=NSURLErrorDomain Code=-999 “cancelled” · Issue #2178 · Alamofire/Alamofire · GitHub

还是不是完全懂。

去搞清楚:

ios weak self vs unowned self

What is this `[unowned self] in` Swift code doing? – Stack Overflow

“It lets you avoid retain cycles caused by closures that have a strong reference to the object that creates them, when the creating object also has a strong reference to the closure.”

-》好像是:

对于实例本身,是强引用自己-》就导致了循环引用?

-》感觉也不对啊:类中的代码中每个函数都是self,都是强引用自己啊。

The Swift Programming Language (Swift 4): Automatic Reference Counting

“Resolving Strong Reference Cycles for Closures

You resolve a strong reference cycle between a closure and a class instance by defining a capture list as part of the closure’s definition. A capture list defines the rules to use when capturing one or more reference types within the closure’s body. As with strong reference cycles between two class instances, you declare each captured reference to be a weak or unowned reference rather than a strong reference. The appropriate choice of weak or unowned depends on the relationships between the different parts of your code.

NOTE

Swift requires you to write self.someProperty or self.someMethod() (rather than just someProperty or someMethod()) whenever you refer to a member of self within a closure. This helps you remember that it’s possible to capture self by accident.”

官网都解释了:

对于闭包函数中,存在强引用的问题

解决的办法是:

在闭包函数中,使用capture list,定义对应的weak或unowned的self,即可。

具体用weak还是unowned,取决于具体情况。

当closure和类的实例总是互相引用时,也常常同时被销毁,则用unowned。

而当类的实例,则未来的某个时间,可能会变成nil,则使用weak。

weak的变量,则始终都是个optional类型。

注:如果对应的(被capture的实例)永远都不会变成nil,则应该用unowned,而不应该用weak。

而官网举的HTMLElement的例子,还是不太懂。

算了,试试从头开始看这个资料吧:

The Swift Programming Language (Swift 4): Automatic Reference Counting

尽量去搞懂。

Swifter – Swift 必备 tips

“Weak, Strong, Unowned, Oh My!” – A Guide to References in Swift — KrakenDev

“WEAK, STRONG, UNOWNED, 老天爷!” – SWIFT中的引用关系说明 – 简书

ios – Shall we always use [unowned self] inside closure in Swift – Stack Overflow

有一点点理解了:

对于:

class TempNotifier {
var onChange: (Int) -> Void = {_ in }
var currentTemp = 72
init() {
    onChange = { [unowned self] temp in
self.currentTemp = temp
    }
}
}

如果不用unowned self,则会造成内存泄漏的原因是:

如果不用unowned self,此处的closure闭包函数本身:

{ temp in
self.currentTemp = temp
    }

也会 引用到 self=当前的类的实例=TempNotifier的实例

-》这就导致,即使没有其他类去引用TempNotifier,但是TempNotifier实例还是会被此处的闭包函数引用着,ARC引用计数不是0,导致无法释放内存,造成内存泄漏,所以此处要用非强引用

-》而用unowned而不是weak,则是因为:

此处确保self始终不是nil,如果self是nil,则本身onChange事件也都不存在了,所以此处应该用unowned。

而对于另外的网络(Alamofire的http请求)函数来说:

当网络函数request被调用后,过段时间才返回,则返回时,其实希望类的实例self是存在的,

所以是强引用,而且是在后续处理完毕后,函数返回,就不再引用该类的实例了。

而如果是弱引用,则可能会出现:

Alamofire的http的返回response后,self对应的类的实例已经不在了,则无法继续处理了,则不应该出现这个情况。

除非别人说的:

当网络请求返回时,可能会生成新的ViewController时,但是用户却页面返回,该页面消失了,则此时才不会继续去处理,不应该强引用该类,应该用弱引用。

截至目前,其实还是有点晕,没完全懂。

继续看官网去学习。

又看懂了点:

【理解】

对于closure来说,只有当:

一个类(的实例)中,有个属性(是函数类型)

然后你把一个(等价于函数的)closure,赋值给该属性时,

而closure的函数体中,包含了,引用了self=该类的实例,

则就造成了循环引用了。

就像

ios – Shall we always use [unowned self] inside closure in Swift – Stack Overflow

提到的官网中举例的:

class TempNotifier {
  var onChange: (Int) -> Void = {_ in }
  var currentTemp = 72
  init() {
    onChange = { [unowned self] temp in
      self.currentTemp = temp
    }
  }
}

类TempNotifier中包含了个函数属性onChange

而onChange是个闭包函数

{ temp in
      self.currentTemp = temp
    }

该闭包函数的函数体中的:

self.currentTemp

引用了类TempNotifier的currentTemp的属性

-》从而导致了循环引用

-》所以要加上:

[unowned self]

变成:

{ [unowned self] temp in
      self.currentTemp = temp
    }

去规避避免了循环引用。

-》而此处自己的代码中,尤其是典型的普通的Alamofire的http的返回的闭包函数中,比如:

class TaskViewController: xxx {
    func  getTaskList(){
        getUrlRespJson_async(
            httpMethod: .get,
            url: url,
            parameters: nil,
            respJsonHandle: { [weak self] (response) in
                self?.getTasksCount()
            }
        }
    }
}

是不存在这种循环引用的。

所以,response中,根本没有必要写成weak或unowned的self

所以去改为:

            respJsonHandle: {(response) in
                self.getTasksCount()
            }

即可。

把self?改为self即可。

【总结】

基本总结如下:

1.只有两个类,直接的或间接的,互相循环引用而导致内存泄漏,才需要用到weak后unowned去解决和打破循环引用的问题。

至于是用weak还是unowned:

对于类似于:

Person人,和公寓Apartment

的关系,互相引用的对方,在未来的某个时间,可能会变成nil,则使用weak

对于类似于:

Customer客户 和 信用卡CreditCard

的关系,一方永远会比另一方活得时间(存在的时间)长,则获得短的(CreditCard)中引用长的(Customer),使用unowned -》即在短的CreditCard引用长的Customer期间,永远不会遇到nil的情况。

2.对于常见的,典型的Alamofire的http的response的closure来说,不需要用weak(或unowned)self。

注:

还是那句原则:

只有出现了循环引用,比如closure的函数中引用到了当前类self(的属性或函数)而closure又被赋值给当前类作为一个属性了,才会使用weak或unowned。

转载请注明:在路上 » 【已解决】Alamofire返回的response中weak self的含义和是否可以去掉

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
100 queries in 0.190 seconds, using 23.37MB memory