在swift4中使用结构体时, 在一个闭包中使用Self内的方法或属性时,会报这样错误
#### “Closure cannot implicitly capture a mutating self parameter”
这是因为swift4没有添加截获列表的原因,其实就是闭包无法保证进出闭包参数的一致性(为什么一致性会不一样你可以去查查swift值类型和引用类型的关系与区别),所以编译器不允许struct在闭包中使用self
一般这种情况有三种解决方案
1. 将类型的struct声明改为class (大多数人都不会选择,这样就将对象从值类型变为了应用类型,可能就改变了我们使用这个类型的初衷,所以不推荐使用)
2.增加一个inout类型的参数 举个例子:
// 这是一个通过Url加载图片的方法 结果返回个带有图片的闭包 func loadImage(imageUrl: String, finish: ((UIImage?)->())?) { // 这里做加载图片的处理 }/* 存储图片的结构体 要求图片Url在设置时自动给image赋值 */ struct ImageSource { var imageURL: String = "" { didSet { setImage(&self) } } var image: UIImage? mutating func setImage(inSelf: inout ImageSource) { loadImage(imageUrl: imageURL, finish: { (image) in inSelf.image = image }) }}
这种方案虽然也能解决问题但是多了不比必要的内存消耗,inout的声明操作是重新生成一份Self的复制,然后进行修改,修改完成后重新将复制出来的对象赋值self,如果struct比较大,那么就这样做就很不划算
3.使用UnsafeMutablePointer 同样举个例子:
// 这是一个通过Url加载图片的方法 结果返回个带有图片的闭包 func loadImage(imageUrl: String, finish: ((UIImage?)->())?) { // 这里做加载图片的处理 } /* 存储图片的结构体 要求图片Url在设置时自动给image赋值 */ struct ImageSource { var imageURL: String = "" { didSet { setImage() } } var image: UIImage? func setImage() { // 拿到self的指针 let unsafePointSelf = UnsafeMutablePointer(&self) loadImage(imageUrl: imageURL, finish: { (image) in // 进行指针赋值 unsafePointSelf.pointee.image = image }) }}
这种方式是使用指针进行内存复制,优点是没有多余的内存消耗,性能也高,也不会违背你使用struct的初衷。但是使用UnsafeMutablePointer代表着你必须保证自己代码的安全性,个人推荐使用该方式。