unwindFrom的线程问题

时间:2017-11-02 12:48:00

标签: ios xcode multithreading thread-safety uipresentingcontroller

我的问题的高级摘要:

我有一个UITableViewController(TVC1)执行performSegue来调用静态UITableViewController(TVC2),以便用户可以输入详细信息。按下名为&#34的按钮后,再添加另一个"在TVC2上,我希望TVC2保存其数据并再次调用以添加另一条记录。

详细信息:

我有一个tableViewController(TVC1)来实现这个数据模型:

- Category <=> maps to tableview sections
  - Group <=> maps to tableview rows
    - Detail <=> maps to tableview rows

显示器可能如下所示:

- Section 0: Category 1
  - Row 0: Group A
  - Row 1: Detail x1
  - Row 2: Detail y2
  - Row 3: Detail z3
  - Row 4: Group B
  - Row 5: Detail x2
  - Row 6: Detail y2
  - Row 7: Detail y3

例如,当我想通过点击详细信息第5行来修改详细信息时,我会在performSegue中执行didSelectRowAt

TVC1.prepareForSegue我提供TVC1作为TVC2的代表,可以添加/编辑该细节。我还提供了要编辑的细节数据到TVC2的属性。

在TVC2上 - 提供详细信息后 - 用户可以单击工具栏中的保存按钮,这将保存数据并将他带回TVC1。或者,在可以输入详细信息的表单末尾,我有一个按钮:

  • 添加其他详细信息

这个想法是用户直接进入新屏幕,在那里他们可以为同一组添加另一个细节。所以基本上在TVC2消失之后,它应该再次出现以添加新的细节。

在TVC2中,我将此按钮链接到TVC1上的unwindFrom方法。然后在TVC2的prepareForSegue中,我在委托(TVC1)上调用协议方法以提供已编辑的详细信息并提供称为NextAction的结构,以通知根TVC1其下一步应该是什么。在这种情况下,它应该在同一组中添加另一个细节。

然后在TVC1的unwindFrom方法中,我查看nextAction并启动下一个performSegue

我不知道有另一个地方可以做到这一点。对我而言,这是我可以提出下一个动作的最后一个动作,即TVC2。

这会导致奇怪的行为。它似乎工作一次,但不是第二次。

调试显示(=====&gt;行是我自己的打印调试行):

========> TVC2 prepare start (means the add more details button was pressed)
========> TVC1 newDetailValues begin (TVC2 calling the delegate protocol method to provide back edited data - including NextAction)
========> TVC1 newDetailValues end
========> TVC2 prepare end (I am not sure if TVC2 is now closed/inaccessible)
========> TVC1 unwindFromAddEdit begin (here nextAction is evaluated and a performSegue done)
========> TVC1 prepare begin (initiated by the performSegue)
========> TVC1 prepare end
'Presenting view controllers on detached view controllers is discouraged <Project.TVC1: 0x.........>.'
========> TVC1 unwindFromAddEdit end

请注意错误/警告:

'Presenting view controllers on detached view controllers is discouraged <Project.TVC1: 0x.........>.'

但我确实看到了TVC2的细节。但是当我再次点击按钮时,它会显示根TVC1而不是TVC2。 xcode现在说:

'Warning: Attempt to present <UINavigationController: 0x.........> on <Project.TVC1: 0x.........> whose view is not in the window hierarchy!'

我对线程有这种感觉 - 可能是TVC1.unwindFrom在TVC2范围内运行的地方。

当我编辑TVC1.unwindFrom并替换:

performSegue(withIdentifier: "AddDetails", sender: self)

... with:

DispatchQueue.main.async {
   performSegue(withIdentifier: "AddDetails", sender: self)
}

一切正常。

可是:

  1. 我不明白发生了什么。
  2. 我无法评估我所做的事情是否是线程安全的。例如:我是否在TVC2关闭和TVC1同时呼叫TVC2之间引入竞争条件?
  3. 谁可以为正在发生的事情发光?

1 个答案:

答案 0 :(得分:0)

答案由Paulw11在评论中提供:

当按下“添加另一个”按钮时,每次调用TVC2后,最好不要放松。

相反,应该将“添加另一个”按钮控制拖动到同一导航控制器并以模态方式执行。

在prepareForSegue中,可以将TVC2所需的详细信息从当前的ViewController复制到自身的新实例。

在某些时候,用户使用工具栏中的CANCEL或SAVE按钮,将所有内容展开到TVC1。

这样做也会使UI看起来更干净,因为TVC1的展开不可见。