在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代表着你必须保证自己代码的安全性,个人推荐使用该方式。