use*_*684 2 swift xcode7 swift2 xcode7-beta2
我刚刚下载了Xcode 7 Beta 2,并且正在尝试使用我对Swift的了解来创建一个应用程序来删除用户相机胶卷中的照片.我知道如何使用Swift 1.2正常工作,但我似乎无法在Swift 2.0中获得它.我尝试搜索文档以了解如何在Swift 2.0中使用'performChange'函数,但它不起作用.这是我的Swift:
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
PHAssetChangeRequest.deleteAssets(arrayToDelete)
}, completionHandler: { (success, error) -> Void in
NSLog("Finished deleting asset. %@", (success ? "Success" : error))
})
Run Code Online (Sandbox Code Playgroud)
这是我的错误:
无法
performChanges使用类型的参数列表调用(() -> _, completionHandler: (_, _) -> Void)
任何帮助表示赞赏!!
Swift编译器通常在报告复杂表达式中类型检查失败的正确根本原因时遇到问题.我不会简单地向您展示此代码的正确形式,而是将介绍我如何找到这种方式的方式,以便您可以重用该过程以供将来调试.(如果必须,请跳过TLDR.)
首先,你有一个错误的形式:
无法使用'params'类型的参数列表调用'function '
这意味着有关函数调用的内容无法进行类型检查.因为您正在调用参数包含闭包的函数,所以您需要查看闭包的行为以缩小类型检查问题的范围.
让我们首先明确返回闭包Void:
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
PHAssetChangeRequest.deleteAssets(arrayToDelete)
return
}, completionHandler: { (success, error) -> Void in
NSLog("Finished deleting asset. %@", (success ? "Success" : error))
return
})
Run Code Online (Sandbox Code Playgroud)
这里发生了什么?您已经将完成处理程序的类型声明为返回Void,那么为什么要使用额外的return语句?Swift类型检查既可以自下而上,也可以自上而下,如果两种方式都有错误,则无法对另一方进行假设.在这里,你有两个单表达式闭包,因此Swift必须考虑每个单独的表达式可能是一个隐式的return语句.
如果其中一个语句有类型检查错误,那么该语句的返回类型就变成了<<error type>>,并且因为它是单语句闭包,闭包的返回类型变为<<error type>>,因此闭包是一个参数的函数调用失败,因为函数期待一个返回Void的闭包,而不是一个返回的闭包<<error type>>.
确实发生了这种情况 - 一旦我们做出上述改变,我们就会在NSLog声明中"Success"突出显示不同的错误(突出显示):
'_'不能转换为'StringLiteralConvertible'
这有点不清楚,但我们更接近问题的根源.如果(success ? "Success" : error)用一些静态的东西替换log语句的部分(比如说,只是"Success"),它就会编译.所以,让我们分开并剖析那个三元运算,看看里面出了什么问题.
let successString = "Success"
let report = (success ? successString : error)
NSLog("Finished deleting asset. %@", report)
Run Code Online (Sandbox Code Playgroud)
这使得我们?在三元运算符上出现了一个新的错误:
'NSString'不是'NSError'的子类型
咦?一件用自动转换做的Swift.String到NSString,也许?让我们明确表明转换:
let successString = "Success" as NSString
let report = (success ? successString : error)
Run Code Online (Sandbox Code Playgroud)
没有更多上下文,表达式的类型是模糊的
现在我们达成了问题的关键.事实上,report应该是什么类型?如果success是真的,那就是NSString,但如果是假的,那就是NSError?(error从声明中推断出来的类型performChanges(_:completionHandler:)).这种类型的手部波纹将在C中飞行,但Swift对此类事物要严格得多.(有人非常明智地说过,"不完整的类型规范导致内存布局不清晰,内存布局不清晰导致未定义的行为,未定义的行为导致痛苦." 或类似的东西.)
两者唯一的超NSString和NSError?是Any,和斯威夫特不愿推断该类型.(因为如果你推断一切都可以是任何东西,你的类型信息就毫无价值.)如果你试图手动使用那种类型,当你尝试将它传递给时会出现错误NSLog:
let report: Any = (success ? successString : error)
NSLog("Finished deleting asset. %@", report)
Run Code Online (Sandbox Code Playgroud)
无法使用类型为'(String,Any)'的参数列表调用'NSLog'
期望一个类型'(String,[CVarArgType])'的参数列表
这些错误让我们失去了C vararg函数的兔子洞,所以让我们退一步 - 这个论点NSLog真的需要什么类型?NSLog是一个ObjC函数,内置格式字符串替换(%@业务)NSString stringWithFormat.根据文档,当您使用%@令牌时,NSString在相应的参数中查找对象并调用其description方法.因为这个实现是ObjC和Cocoa框架的一部分(可以追溯到恐龙被消灭之前),而不是Swift的东西,所以有理由认为纯粹的Swift类型Any在这里不起作用.
NSObject将是一个很好的Cocoa类型传递给NSLog函数.但是,声明作为report不会飞的类型- 你不能隐式地将三元运算符的两个分支转换为NSObject.该error参数是可选的 - 它的推断类型是NSError?,还记得吗?这是一个Swift类型,而不是Cocoa类型.
所以这是最后一个问题 - 你有一个三元运算符试图让一个分支成为一个完全合理的对象,另一个分支是一个仍然包装的可选项.实际上,强制解包可选项会清除所有编译器错误:
let report = (success ? successString : error!) // report now type-infers NSObject
NSLog("Finished deleting asset. %@", report)
Run Code Online (Sandbox Code Playgroud)
现在我们已经修好了所有东西,我们可以把车轮重新打开并将所有东西倒塌......
PHPhotoLibrary.sharedPhotoLibrary().performChanges({
PHAssetChangeRequest.deleteAssets(arrayToDelete)
}, completionHandler: { success, error in
NSLog("Finished deleting asset. %@", (success ? "Success" : error!))
})
Run Code Online (Sandbox Code Playgroud)
我们知道,由于API合同,强制解包这里是安全的:如果success为真,则为errornil,但如果success为false,则实际上会出现错误.
(这可能甚至没有performChanges(_:completionHandler:)解开以前的SDK版本,因为在Apple审核所有API的可空性之前,它中的闭包类型会使用隐式解包的可选项.)
| 归档时间: |
|
| 查看次数: |
1062 次 |
| 最近记录: |