我在swift中有一个懒惰的属性,它有一个看起来像这样的回调。
lazy var apiClient: MyApiClient =
{
var apiClient : MyApiClient = MyApiClient()
apiClient.detailSearchFinishedCallBack = {
(detailModel : DetailModel!) in
}
return apiClient
}()
我有另一个懒惰的load属性,我想在闭包内访问,如下所示:
lazy var loadingView : LoadingView =
{
var loadingView : LoadingView = LoadingView()
loadingView.frame = CGRectMake(0, 0, 200, 200)
loadingView.center = self.view.center
return loadingView
}()
但是,我无法引用闭包内的加载视图。在目标c中,这看起来像这样。
-(LoadingView *)loadingView
{
if(!_loadingView)
{
_loadingView = [LoadingView new];
_loadingView.frame = CGRectMake(0, 0, 200, 200);
_loadingView.center = self.view.center;
}
return _loadingView;
}
-(MyApiClient *)apiClient
{
if(!_apiClient)
{
_apiClient = [MyApiClient new];
__weak FeedViewController *_self = self;
self.apiClient.detailSearchFinishedCallBack = ^(DetailModel *detailModel)
{
[_self.loadingView stopAnimating];
};
}
return _apiClient;
}
有人能够在Swift中向我展示相同的内容吗?
更新
lazy var apiClient: MyApiClient = {
let apiClient: MyApiClient = MyApiClient()
apiClient.detailSearchFinishedCallBack = { [weak self] (detailModel: DetailModel!) in
println(self?.loadingView.frame)
return
}
return apiClient
}()
所以我继续尝试实现提议的解决方案,但是我收到了编译错误。特别是我遇到了这个错误:
命令/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc失败,退出代码为1
我不确定这是否与我的项目中的swift配置有关,但是我使用桥接标头导入我的目标c头文件以暴露给Swift。我无法想到任何其他可能导致这种情况的事情,但任何帮助都会得到解决。
答案 0 :(得分:2)
语法为:
lazy var apiClient: MyApiClient = {
let apiClient: MyApiClient = MyApiClient()
apiClient.detailSearchFinishedCallBack = { [weak self] detailModel in
self?.loadingView?.stopAnimating()
}
return apiClient
}()
当我最初回答这个问题时,Swift编译器在解释上述语法时遇到了问题,因此我提出了下面概述的以下丑陋的解决方法。但您现在可以使用上述简单的逻辑语法。
原始答案:
您正在使用闭包为属性提供默认值。但是在 Swift编程语言的Initialization章节的设置带闭包或函数的默认属性值部分中说:
注意:如果使用闭包初始化属性,请记住在执行闭包时尚未初始化实例的其余部分。这意味着您无法从闭包中访问任何其他属性值,即使这些属性具有默认值也是如此。您也不能使用隐式
self
属性,也不能调用任何实例的方法。
话虽如此,人们可以提出一个论点,即编译器应该允许惰性变量,但它并没有。
你说你想要实现这个Objective-C代码:
-(MyApiClient *)apiClient
{
if(!_apiClient)
{
_apiClient = [MyApiClient new];
__weak FeedViewController *_self = self;
self.apiClient.detailSearchFinishedCallBack = ^(DetailModel *detailModel)
{
[_self.loadingView stopAnimating];
};
}
return _apiClient;
}
也许您可以考虑使用由计算属性处理的私有存储属性进行更直接的Swift转换:
private var _apiClient: MyApiClient!
var apiClient: MyApiClient {
if _apiClient == nil {
_apiClient = MyApiClient()
_apiClient.detailSearchFinishedCallBack = { [weak self] detailModel in
if let loadingView = self?.loadingView {
loadingView.stopAnimating()
}
}
}
return _apiClient
}
请注意,这不是线程安全的(但您的Objective-C再现也不是),但它可以完成您的要求。
另外还有其他方法可以解决这个问题:
您可以将初始化代码从这些闭包中移动到其他逻辑共享初始化例程中,例如: viewDidLoad
或者你有什么。这样,事物初始化的顺序是明确且明确的。
您可以通过API发布视图可以观察到的通知来进一步将API与UI分离。
答案 1 :(得分:0)
我不确定你无法做什么。
实际上,Xcode在self
模式中使用lazy var x:Type = { ... }()
时遇到了一些问题。例如,它不会自动完成属性或方法,但它可以工作。
此代码在Xcode 6.3 Beta2中编译和工作:
class LoadingView: UIView {}
class DetailModel {}
class MyApiClient {
var detailSearchFinishedCallBack: ((DetailModel!) -> Void)?
}
class MyViewController1: UIViewController {
override func viewDidLoad() {
self.apiClient.detailSearchFinishedCallBack?(DetailModel())
}
lazy var apiClient: MyApiClient = {
let apiClient: MyApiClient = MyApiClient()
apiClient.detailSearchFinishedCallBack = { [weak self] (detailModel: DetailModel!) in
println(self?.loadingView.frame)
return
}
return apiClient
}()
lazy var loadingView: LoadingView = {
let loadingView: LoadingView = LoadingView(frame: CGRectMake(0, 0, 200, 200))
loadingView.center = self.view.center
return loadingView
}()
}
对于Xcode 6.1.1,由于某些原因,编译器崩溃了。看来,我们必须在闭包之外至少引用一次self
。
self // <- reference `self` in anyway
apiClient.detailSearchFinishedCallBack = { [weak self] (detailModel: DetailModel!) in
println(_self?.loadingView.frame)
return
}
最后,如果你觉得不安全,你可以做直截了当的Objective-C:
class MyViewController2: UIViewController {
private var _apiClient: MyApiClient? = nil
var apiClient: MyApiClient {
if _apiClient == nil {
let apiClient : MyApiClient = MyApiClient()
apiClient.detailSearchFinishedCallBack = { [weak self] (detailModel : DetailModel!) in
println(self?.loadingView.frame)
return
}
_apiClient = apiClient
}
return _apiClient!
}
private var _loadingView: LoadingView? = nil
var loadingView : LoadingView {
if _loadingView == nil {
let loadingView : LoadingView = LoadingView(frame: CGRectMake(0, 0, 200, 200))
loadingView.center = self.view.center
_loadingView = loadingView
}
return _loadingView!
}
}