Swift:NSUserDefaults 没有立即设置
Posted
技术标签:
【中文标题】Swift:NSUserDefaults 没有立即设置【英文标题】:Swift: NSUserDefaults not setting straight away 【发布时间】:2016-02-29 14:55:35 【问题描述】:我有什么
我有一个视图控制器 (SelectNameViewController),上面有一个 UITableView 和一个名称列表。当用户点击一个名字时,它会转到一个 ViewController (ResultController),它有一个容器视图,可以加载 3 个 ViewControllers (vc1,vc2, vc3) 允许用户滚动浏览。
在 ResultController 我有一个连接到 JSON 文件并根据所选名称下载信息的 alamofire 请求:
Alamofire.request(.GET, sendyURLSet, parameters: ["name": passedName, "api_key": api_key])
.responseJSON response in
switch response.result
case .Success:
if let value = response.result.value
let json = JSON(value)
self.age = json["age"].stringValue
self.userInfo.setValue(self.age, forKey: "age")
case .Failure(let error):
print(error)
在 VC1 我的 viewDidAppear
中有这个if let a = userInfo.stringForKey("age")
print("Age: \(a)")
else
print("nope")
问题
在从 Alamofire 请求加载内容后,我无法在 PageViewController 子视图上加载数据。
当用户单击一个名称并被带到 ResultController 时,3 个视图会加载到容器视图中。出现的第一个屏幕是 vc1。
但是,在控制台中我只是得到:
没有
如果我滑动到 vc2 然后回到 vc1 我会得到:
32 岁
在控制台中。
问题
谁能告诉我为什么 ViewController (vc1) 的第一个演示文稿中没有显示该值并告诉我如何解决它?
快把我逼疯了
【问题讨论】:
不要使用NSUserDefaults
在控制器之间传递数据。使用 segues、协议 - 委托模式或通知(按推荐优先级顺序)
三个视图控制器在加载到容器视图时没有转场。
【参考方案1】:
看起来 vc1 的加载速度比数据提取完成的速度快。
要么等待数据加载完毕再加载新的控制器,要么数据完成后直接设置标签
【讨论】:
【参考方案2】:很可能,对您的Alamofire.request
的回调是在viewDidAppear
之后调用的,这就解释了为什么您看不到您在回调中设置的值。
你应该想要的是你的代码
if let a = userInfo.stringForKey("age")
print("Age: \(a)")
else
print("nope")
在回调执行后调用。
你有几种方法:
resultsController
调用 VC1
以使其更新其 UI;
从回调中加载resultsController
(实际上,您确保在回调中第一次调用它的view
方法,即当您将其作为子视图添加到父视图时);
或者,您使用KVO
使VC1
观察对userInfo.age
的任何更改。这种方法需要通过从 NSUserDefaults
派生一个新类来自定义 NSUserDefaults
。
【讨论】:
我认为这与请求有关。我如何从 vc1 等待视图(ReportsView)在加载数据之前完成它的业务? 我对此有点小菜鸟,所以非常感谢您的帮助:) 请看我提到的 3 个选项。 好的,所以对于选项 3 (KVO),我是否相信该选项仅适用于 NSObject 类?所以这行不通,对吧?选项 2: resultsController 中有 alamofire 代码,所以可以重新加载视图吗?这不会造成重复循环吗?这留下了选项 1 - 我不确定如何“调用”视图控制器。有什么指点吗? KVO 实际上可以在 Swift 中工作,没有问题 - 但如果您从未使用过 KVO(在 Swift 或 ObjC 中),那么它无疑是最难的选择。至于选项 2,我知道resultsController
在某些时候会实例化 VC1
并将其添加为子视图。是对的吗?您应该从回调中运行该代码。至于选项3,只需在resultsController
的属性中保留对VC1
的引用,然后在回调中对该引用调用viewDidAppear
(或者更好的是,定义一个临时方法,例如updateUI
,那会更干净)【参考方案3】:
尝试以下一个。我想它可能会对你有所帮助。
网络调用完成后(在完成处理程序块中),使用 outlet 为 UI 元素(如标签)设置值。并调用- (void)setNeedsLayout
方法。该方法表示图层的子图层的布局发生了变化,必须更新。当图层的边界发生变化时,系统通常会自动调用此方法。
【讨论】:
以上是关于Swift:NSUserDefaults 没有立即设置的主要内容,如果未能解决你的问题,请参考以下文章
在 Swift 中使用 NSUserDefaults 保存 NSMutableArray 返回 Nil
Swift - 将字典数组保存到 NSUserDefaults
Swift:将 NSDictionary 保存到文件中,因为 NSUserDefaults 会变慢
无法从 NSUserDefaults 检索数据到今天的扩展(Swift)