【问题标题】:Variable instantiated in prepare for Segue has nil properties in ViewDidLoad在为 Segue 做准备时实例化的变量在 ViewDidLoad 中具有 nil 属性
【发布时间】:2016-04-12 09:48:21
【问题描述】:

我的视图控制器在模型中的核心位置数据可用之前加载。

我有一个主视图控制器,它以模态方式推送一个带有两个 NSManagedObject 子类(记录和位置)的新视图控制器,它们在 prepareForSegue 方法中实例化。

if segue.identifier == "newRecord"
    {
        let controller = (segue.destinationViewController as! NewRecordVC)

        let appDelegate    = UIApplication.sharedApplication().delegate as? AppDelegate     // instantiate the delegate methods in AppDelegate

        let managedContext = appDelegate!.managedObjectContext      // create context from delegate methods

        let recordEntity = NSEntityDescription.entityForName("RecordData", inManagedObjectContext: managedContext)
        let locationEntity = NSEntityDescription.entityForName("Location", inManagedObjectContext: managedContext)

        controller.location = Location(entity: locationEntity!, insertIntoManagedObjectContext: managedContext)
        controller.record = Record(entity: recordEntity!, insertIntoManagedObjectContext: managedContext)
        controller.managedContext = appDelegate?.managedObjectContext
        print("segueing")
    }

两个托管对象都有inits 用于各种值。记录具有分配给显示在新视图上的属性的简单预分配值。然而,位置属性主要需要位置服务来分配属性值。打印属性值表明,虽然在viewDidLoad 中实例化了位置,但位置服务分配的位置属性仍然为零。位置服务正在工作 - 属性从模型内打印,但这是在 viewDidLoad 之后。在加载时,我至少需要 geoPlacemark 属性,它为视图提供文本。

    override func viewDidLoad()
{
    super.viewDidLoad()
    ...
    if let recordNotNil = record
    {
        ...
        iD.text = "ID: \(recordNotNil.iD)"
    }

    if let locationNotNil = location
    {
        ...
        print("bing")
        print(locationNotNil.temp)
        record!.location = location!
        print(location.geoPlacemark)
        print(location.timestamp)
        if let geoPlacemarkNotNil = location.geoPlacemark
        {
            print("bong")
            locationText(geoPlacemarkNotNil)
        }
    }
}

我是否必须在每个视图控制器而不是模型中运行定位服务?或者有没有办法让视图等待位置委托方法?

【问题讨论】:

  • 当您传递托管对象上下文时,在viewDidLoad 的目标视图控制器中创建 CoreData 对象可能会更容易。
  • 我试过这个,但事件的顺序仍然存在:Segue to VC; viewDidLoad 已分配基本属性值,但未分配核心位置属性值 (nil);允许定位服务的警报;然后我从 didUpdateLocations 获取数据,包括地标。

标签: ios swift model-view-controller core-location


【解决方案1】:

prepareForSegue() 中,destinationViewController 已经实例化,并且viewDidLoad() 已经被调用。 如果你想设置一个标签,你真的应该在viewWillAppear()

override func viewWillAppear() {
    super.viewWillAppear()

    // Set up your views here
}

viewWillAppear() 相对于viewDidLoad() 的另一个好处是每次 ViewController 即将出现时都会调用它,这可以在 VC 生命周期中多次调用 - 而不是在 VC 的开始时调用一次viewDidLoad() 的生命周期。

【讨论】:

  • 可悲的是,这似乎并没有改变它。事件的顺序仍然存在:Segue to VC; viewWillAppear 具有基本属性,但没有位置服务数据 (nil);没有更新位置;最后是 geoPlacemark。
  • prepareForSegue中成功创建位置和记录对象能否签入调试器?
  • 记录被实例化 - 这些属性值出现在视图上。我在 location 属性上进行可选链接,并且可以打印到控制台(甚至是简单的属性值,而不是位置值)。
  • 我注意到我明白了。你是说prepareForSegue你成功实例化了Record对象但是Location对象实例化失败了?还是我弄错了?
  • 两者似乎都在实例化。我可以在 viewWillLoad 或 viewDidLoad 中打印非位置属性值(例如,任意字符串值),但我无法打印任何核心位置派生属性值。我只能从位置委托方法中打印这些值。
【解决方案2】:

这里的问题来自对 NSManagedObject 使用正常的覆盖初始化方法。

class Record: NSManagedObject
{
override init(entity: NSEntityDescription, insertIntoManagedObjectContext context: NSManagedObjectContext?)
{
    super.init(entity: entity, insertIntoManagedObjectContext: context)
    let randomBit = String(arc4random_uniform(100))
    iD = NSDate().toIDTimeDateString() + "-" + randomBit + "OtR"

    believers = 0
    deviceTime = NSDate()
    doubters = 0
    eventTimeStarted = NSDate()
    eventTimeEnded = NSDate()
    featureImageIndex = 0
    coreLocationUsed = 0
    photoTaken = 0
    tableSection = "My Records"
    timeRecorded = deviceTime
    validationScore = 0
}
}

根据apple doc.s,应使用 awakeFromInsert 或 awakeFromFetch 启动自定义 NSManagedObjects。

【讨论】:

    猜你喜欢
    • 2017-05-30
    • 2014-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多