如何从父视图控制器多次传递数据到Swift中的VC孩子? [英] How to Pass Data Multiple Times from Parent View Controller to Container VC Child in Swift?

查看:816
本文介绍了如何从父视图控制器多次传递数据到Swift中的VC孩子?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在ViewControllerA(Parent)上有一个按钮,我想更新ViewControllerB(Child)中的一个变量。 ViewControllerB是ViewControllerA里面的容器视图。



这是ViewControllerB中的变量我想从Parent ViewControllerA按钮中多次更新:

  @IBOutlet weak var childViewHeight:NSLayoutConstraint! 

因为子视图ViewControllerB通过嵌入segue连接,似乎我只能传递数据从ViewControllerA到ViewControllerB,通过 prepareForSegue 方法。 performSegue 方法会导致程序与 SIGABRT 错误一起崩溃。



我知道一般认为不好的做法是尝试从一个单独的类或视图控制器更新一个 IBOutlet ,但我需要一个方法按下ViewControllerA同时更改ViewControllerA和ViewControllerB的高度约束。



如果这在我目前的方法是不可能的,请给我另一个建议如何重新设计我的应用程序,使这可能。



更新 - 这是导致崩溃的代码:

  @IBAction func button(_ sender:AnyObject){
performSegue(withIdentifier:seg,sender:self)
}


更新 - 这是在调试控制台中输入bt时的结果:

  * thread#1:tid = 0x1fcdd,0x000000010d9b1f06 libsystem_kernel.dylib`__pthread_kill + 10,queue ='com.apple.main-thread',stop reason = signal SIGABRT 
frame#0:0x000000010d9b1f06 libsystem_kernel.dylib `__pthread_kill + 10
帧#1:0x000000010dad24ec libsystem_pthread.dylib`pthread_kill + 90
帧#2:0x000000010d7040b3 libsystem_c.dylib`abort + 129
帧#3:0x000000010d9d043a的libc ++ ABI。 dylib`abort_message + 266
frame#4:0x000000010d9f4a9f libc ++ abi.dylib`default_terminate_handler()+ 267
frame#5:0x000000010c7b559f libobjc.A.dylib`_objc_terminate()+ 103
帧#6:0x000000010d9f1c09 libc ++ abi.dylib`std :: __ terminate(void(*)())+ 8
frame#7:0x000000010d9f1894 libc ++ abi.dylib `__cxa_rethrow + 99
frame #8:0x000000010c7b54b7 libobjc.A.dylib`objc_exception_rethrow + 40
帧#9:0x000000010a2eebf1 CoreFoundation`CFRunLoopRunSpecific + 433
帧#10:0x000000010f6d7a48 GraphicsServices`GSEventRunModal + 161
帧#11:0x000000010ad27e8b UIKit`UIApplicationMain + 159
* frame#12:0x000000010a1c60cf ContainerVC2'main + 111 at AppDelegate.swift:12
frame#13:0x000000010d6586bd libdyld.dylib`start + 1

更新 - 这是bt控制台输出,异常断点就位:

  * thread#1:tid = 0x219bd,0x000000010afca2ee libobjc.A.dylib`objc_exception_throw,queue ='com.apple.main-thread',stop reason = breakpoint 1.1 
frame#0:0x000000010afca2ee libobjc.A.dylib`objc_exception_throw
frame#1:0x0000000108b7dec2 CoreFoundation` + [NSException raise:format:arguments:] + 98
frame#2:0x0000000109079455 Foundation`- [NSAssertionHandler handleFailureInMethod:对象:文件:行号:描述:] + 195
帧#3:0x0000000109f65309 UIKit`__67- [UIStoryboardEmbedSegueTemplate newDefaultPerformHandlerForSegue:] _ block_invoke + 438
帧#4:0x0000000109ce05e4 UIKit`- [UIStoryboardSegueTemplate _performWithDestinationViewController:发送者:] + 453
帧#5:0x0000000109ce03ee UIKit`- [UIStoryboardSegueTemplate _perform:] + 82
帧#6:0x00000001096dc45b UIKit`- [UIViewController performSegueWithIdentifier:sender:] + 99
*帧#7:0x00000001089d99b3 ContainerVC2`ViewController1.button(sender = 0x00007fff57224658,self = 0x00007fcddb707cb0) - > ()+ 131 at ViewController.swift:9
frame#8:0x00000001089d9a26 ContainerVC2` @ objc ViewController1.button(AnyObject) - > ()+ 54 at ViewController.swift:0
frame#9:0x000000010953eb6f UIKit`- [UIApplication sendAction:to:from:forEvent:] + 83
frame#10:0x00000001096bf927 UIKit`- [UIControl sendAction :to:forEvent:] + 67
frame#11:0x00000001096bfc08 UIKit`- [UIControl _sendActionsForEvents:withEvent:] + 388
frame#12:0x00000001096be6aa UIKit`- [UIControl touchesBegan:withEvent:] + 414
frame#13:0x00000001095aabbd UIKit`- [UIWindow _sendTouchesForEvent:] + 1188
frame#14:0x00000001095ac8d6 UIKit`- [UIWindow sendEvent:] + 3984
frame#15:0x000000010955a1e1 UIKit`- [UIApplication的的SendEvent:] + 281
帧#16:0x0000000109d1502f UIKit`__dispatchPreprocessedEventFromEventQueue + 3314
帧#17:0x0000000109d0dc4e UIKit`__handleEventQueue + 4879
帧#18:0x0000000108b1fcb1 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + $ 17 b $ b帧#19:0x0000000108b04c6c CoreFoundation`__CFRunLoopDoSources0 + 556
帧#20:0x0000000108b04156 CoreFoundation`__CFRunLoopRun + 918
帧#21:0x0000000108b03b5d CoreFoundation`CFRunLoopRunSpecific + 285
帧#22:0x000000010deeca48 GraphicsServices`GSEventRunModal + 161
帧#23:0x000000010953ce8b UIKit`UIApplicationMain + 159
帧#24:0x00000001089db0cf ContainerVC2`main + 111处AppDelegate.swift:12
帧#25:0x000000010be6d6bd libdyld。 dylib`start + 1

这里是bt 按钮一次:

  *线程#1:tid = 0x219bd,0x000000010c206607 libc ++ abi.dylib`__cxa_throw,queue = com.apple.main-thread',stop reason = breakpoint 1.2 
frame#0:0x000000010c206607 libc ++ abi.dylib `__cxa_throw
frame#1:0x000000010afca443 libobjc.A.dylib`objc_exception_throw + 341
frame#2:0x0000000108b7dec2 CoreFoundation` + [NSException raise:format:arguments:] + 98
frame#3:0x0000000109079455 Foundation`- [NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 195
帧#4:0x0000000109f65309 UIKit`__67- [UIStoryboardEmbedSegueTemplate newDefaultPerformHandlerForSegue:] _ block_invoke + 438
帧#5:0x0000000109ce05e4 UIKit`- [UIStoryboardSegueTemplate _performWithDestinationViewController:发件人:] + 453
帧#6:0x0000000109ce03ee UIKit`- [UIStoryboardSegueTemplate _perform:] + 82
帧#7:0x00000001096dc45b UIKit`- [UIViewController中performSegueWithIdentifier:发件人:] + 99
*帧#8:0x00000001089d99b3 ContainerVC2`ViewController1.button(发件人= 0x00007fff57224658 ,self = 0x00007fcddb707cb0) - > ()+ 131 at ViewController.swift:9
frame#9:0x00000001089d9a26 ContainerVC2` @ objc ViewController1.button(AnyObject) - > ()+ 54 at ViewController.swift:0
frame#10:0x000000010953eb6f UIKit`- [UIApplication sendAction:to:from:forEvent:] + 83
frame#11:0x00000001096bf927 UIKit`- [UIControl sendAction :to:forEvent:] + 67
frame#12:0x00000001096bfc08 UIKit`- [UIControl _sendActionsForEvents:withEvent:] + 388
frame#13:0x00000001096be6aa UIKit`- [UIControl touchesBegan:withEvent:] + 414
帧#14:0x00000001095aabbd UIKit`- [一个UIWindow _sendTouchesForEvent:] + 1188
帧#15:0x00000001095ac8d6 UIKit`- [一个UIWindow的SendEvent:] + 3984
帧#16:0x000000010955a1e1 UIKit`- [UIApplication的的SendEvent:] + 281
帧#17:0x0000000109d1502f UIKit`__dispatchPreprocessedEventFromEventQueue + 3314
帧#18:0x0000000109d0dc4e UIKit`__handleEventQueue + 4879
帧#19:0x0000000108b1fcb1 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + $ 17 b $ b帧#20:0x0000000108b04c6c CoreFoundation`__CFRunLoopDoSources0 + 556
帧#21:0x0000000108b04156 CoreFoundation`__CFRunLoopRun + 918
帧#22:0x0000000108b03b5d CoreFoundation`CFRunLoopRunSpecific + 285
帧#23:0x000000010deeca48 GraphicsServices`GSEventRunModal + 161
帧#24:0x000000010953ce8b UIKit`UIApplicationMain + 159
帧#25:0x00000001089db0cf ContainerVC2`main + 111处AppDelegate.swift:12
帧#26:0x000000010be6d6bd libdyld。 dylib`start + 1

UPDATE - prepareforsegue 代码:

  override func prepare(for segue:UIStoryboardSegue,sender:AnyObject?){
if segue.identifier = =seg{
var vcB:ViewControllerB?
vcB = segue.desinationViewController as? ViewControllerB
}


解决方案

为嵌入序列调用 performSegue 。当从故事板加载包含视图控制器时,嵌入segue会自动触发。



您可以在包含视图控制器中使用 prepareForSegue 来获取对包含的视图控制器的引用在segue中的 destinationViewController )。一旦你有参考,你可以将它存储在一个属性,并使用它来与它进行交互。我不建议直接更新约束,而是在视图控制器上调用一个更新其约束的函数:

  class ViewControllerA :UIViewController {

var viewControllerB:ViewControllerB?

override func prepareForSegue(segue:UIStoryboardSegue,sender:AnyObject?){
如果segue.identifier ==seg{
self.viewControllerB = segue.destinationViewController as? ViewControllerB
}
}

@IBAction func button(_ sender:AnyObject){
self.viewControllerB?.doSomethingWithHeight(newHeight)
}
}



class ViewControllerB:UIViewController {

@IBOutlet weak var childViewHeight:NSLayoutConstraint!

func doSomethingWithHeight(newHeight:CGFloat){
self.childViewHeight.constant = newHeight
}
}


I have a button on ViewControllerA (Parent) that I want to update a variable inside of ViewControllerB (Child). ViewControllerB is a container view inside of ViewControllerA.

This is the variable in ViewControllerB I want to update multiple times from the Parent ViewControllerA button press:

@IBOutlet weak var childViewHeight: NSLayoutConstraint!

Because the child view, ViewControllerB, is connected by an embed segue, it seems I can only pass data from ViewControllerA to ViewControllerB once via the prepareForSegue method. The performSegue method causes the program to crash with a SIGABRT Error.

I know it is generally considered bad practice to try to update an IBOutlet from a separate class or view controller, but I need a way for a button press on ViewControllerA to change the height constraint for ViewControllerA and ViewControllerB simultaneously.

If this is impossible in my current approach, please give me another suggestion of how to redesign my app to make this possible.

Update - This is the code that causes the crash:

@IBAction func button(_ sender: AnyObject) {
    performSegue(withIdentifier: "seg", sender: self)
}

Update - Here is the result when I type in "bt" in the debug console:

* thread #1: tid = 0x1fcdd, 0x000000010d9b1f06 libsystem_kernel.dylib`__pthread_kill + 10, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
frame #0: 0x000000010d9b1f06 libsystem_kernel.dylib`__pthread_kill + 10
frame #1: 0x000000010dad24ec libsystem_pthread.dylib`pthread_kill + 90
frame #2: 0x000000010d7040b3 libsystem_c.dylib`abort + 129
frame #3: 0x000000010d9d043a libc++abi.dylib`abort_message + 266
frame #4: 0x000000010d9f4a9f libc++abi.dylib`default_terminate_handler() + 267
frame #5: 0x000000010c7b559f libobjc.A.dylib`_objc_terminate() + 103
frame #6: 0x000000010d9f1c09 libc++abi.dylib`std::__terminate(void (*)()) + 8
frame #7: 0x000000010d9f1894 libc++abi.dylib`__cxa_rethrow + 99
frame #8: 0x000000010c7b54b7 libobjc.A.dylib`objc_exception_rethrow + 40
frame #9: 0x000000010a2eebf1 CoreFoundation`CFRunLoopRunSpecific + 433
frame #10: 0x000000010f6d7a48 GraphicsServices`GSEventRunModal + 161
frame #11: 0x000000010ad27e8b UIKit`UIApplicationMain + 159
* frame #12: 0x000000010a1c60cf ContainerVC2`main + 111 at AppDelegate.swift:12
frame #13: 0x000000010d6586bd libdyld.dylib`start + 1

Update - Here is the "bt" console output with the exception breakpoint in place:

* thread #1: tid = 0x219bd, 0x000000010afca2ee libobjc.A.dylib`objc_exception_throw, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x000000010afca2ee libobjc.A.dylib`objc_exception_throw
frame #1: 0x0000000108b7dec2 CoreFoundation`+[NSException raise:format:arguments:] + 98
frame #2: 0x0000000109079455 Foundation`-[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 195
frame #3: 0x0000000109f65309 UIKit`__67-[UIStoryboardEmbedSegueTemplate newDefaultPerformHandlerForSegue:]_block_invoke + 438
frame #4: 0x0000000109ce05e4 UIKit`-[UIStoryboardSegueTemplate _performWithDestinationViewController:sender:] + 453
frame #5: 0x0000000109ce03ee UIKit`-[UIStoryboardSegueTemplate _perform:] + 82
frame #6: 0x00000001096dc45b UIKit`-[UIViewController performSegueWithIdentifier:sender:] + 99
* frame #7: 0x00000001089d99b3 ContainerVC2`ViewController1.button(sender=0x00007fff57224658, self=0x00007fcddb707cb0) -> () + 131 at ViewController.swift:9
frame #8: 0x00000001089d9a26 ContainerVC2`@objc ViewController1.button(AnyObject) -> () + 54 at ViewController.swift:0
frame #9: 0x000000010953eb6f UIKit`-[UIApplication sendAction:to:from:forEvent:] + 83
frame #10: 0x00000001096bf927 UIKit`-[UIControl sendAction:to:forEvent:] + 67
frame #11: 0x00000001096bfc08 UIKit`-[UIControl _sendActionsForEvents:withEvent:] + 388
frame #12: 0x00000001096be6aa UIKit`-[UIControl touchesBegan:withEvent:] + 414
frame #13: 0x00000001095aabbd UIKit`-[UIWindow _sendTouchesForEvent:] + 1188
frame #14: 0x00000001095ac8d6 UIKit`-[UIWindow sendEvent:] + 3984
frame #15: 0x000000010955a1e1 UIKit`-[UIApplication sendEvent:] + 281
frame #16: 0x0000000109d1502f UIKit`__dispatchPreprocessedEventFromEventQueue + 3314
frame #17: 0x0000000109d0dc4e UIKit`__handleEventQueue + 4879
frame #18: 0x0000000108b1fcb1 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
frame #19: 0x0000000108b04c6c CoreFoundation`__CFRunLoopDoSources0 + 556
frame #20: 0x0000000108b04156 CoreFoundation`__CFRunLoopRun + 918
frame #21: 0x0000000108b03b5d CoreFoundation`CFRunLoopRunSpecific + 285
frame #22: 0x000000010deeca48 GraphicsServices`GSEventRunModal + 161
frame #23: 0x000000010953ce8b UIKit`UIApplicationMain + 159
frame #24: 0x00000001089db0cf ContainerVC2`main + 111 at AppDelegate.swift:12
frame #25: 0x000000010be6d6bd libdyld.dylib`start + 1

and here is the "bt" output after I hit the "continue program execution" button once:

* thread #1: tid = 0x219bd, 0x000000010c206607 libc++abi.dylib`__cxa_throw, queue = 'com.apple.main-thread', stop reason = breakpoint 1.2
frame #0: 0x000000010c206607 libc++abi.dylib`__cxa_throw
frame #1: 0x000000010afca443 libobjc.A.dylib`objc_exception_throw + 341
frame #2: 0x0000000108b7dec2 CoreFoundation`+[NSException raise:format:arguments:] + 98
frame #3: 0x0000000109079455 Foundation`-[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 195
frame #4: 0x0000000109f65309 UIKit`__67-[UIStoryboardEmbedSegueTemplate newDefaultPerformHandlerForSegue:]_block_invoke + 438
frame #5: 0x0000000109ce05e4 UIKit`-[UIStoryboardSegueTemplate _performWithDestinationViewController:sender:] + 453
frame #6: 0x0000000109ce03ee UIKit`-[UIStoryboardSegueTemplate _perform:] + 82
frame #7: 0x00000001096dc45b UIKit`-[UIViewController performSegueWithIdentifier:sender:] + 99
* frame #8: 0x00000001089d99b3 ContainerVC2`ViewController1.button(sender=0x00007fff57224658, self=0x00007fcddb707cb0) -> () + 131 at ViewController.swift:9
frame #9: 0x00000001089d9a26 ContainerVC2`@objc ViewController1.button(AnyObject) -> () + 54 at ViewController.swift:0
frame #10: 0x000000010953eb6f UIKit`-[UIApplication sendAction:to:from:forEvent:] + 83
frame #11: 0x00000001096bf927 UIKit`-[UIControl sendAction:to:forEvent:] + 67
frame #12: 0x00000001096bfc08 UIKit`-[UIControl _sendActionsForEvents:withEvent:] + 388
frame #13: 0x00000001096be6aa UIKit`-[UIControl touchesBegan:withEvent:] + 414
frame #14: 0x00000001095aabbd UIKit`-[UIWindow _sendTouchesForEvent:] + 1188
frame #15: 0x00000001095ac8d6 UIKit`-[UIWindow sendEvent:] + 3984
frame #16: 0x000000010955a1e1 UIKit`-[UIApplication sendEvent:] + 281
frame #17: 0x0000000109d1502f UIKit`__dispatchPreprocessedEventFromEventQueue + 3314
frame #18: 0x0000000109d0dc4e UIKit`__handleEventQueue + 4879
frame #19: 0x0000000108b1fcb1 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
frame #20: 0x0000000108b04c6c CoreFoundation`__CFRunLoopDoSources0 + 556
frame #21: 0x0000000108b04156 CoreFoundation`__CFRunLoopRun + 918
frame #22: 0x0000000108b03b5d CoreFoundation`CFRunLoopRunSpecific + 285
frame #23: 0x000000010deeca48 GraphicsServices`GSEventRunModal + 161
frame #24: 0x000000010953ce8b UIKit`UIApplicationMain + 159
frame #25: 0x00000001089db0cf ContainerVC2`main + 111 at AppDelegate.swift:12
frame #26: 0x000000010be6d6bd libdyld.dylib`start + 1

UPDATE - prepareforsegue code:

override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "seg" {
        var vcB: ViewControllerB?
        vcB = segue.desinationViewController as? ViewControllerB
}

解决方案

You don't need to call performSegue for an embed segue. The embed segue is fired automatically when the containing view controller is loaded from the storyboard.

You can use prepareForSegue in the containing view controller to get a reference to the contained view controller (it will be the destinationViewController in the segue). Once you have the reference you can store it in a property and use that to interact with it. Rather than updating the constraint directly, I would suggest that you invoke a function on the view controller that updates its constraint:

class ViewControllerA: UIViewController {

    var viewControllerB: ViewControllerB?

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "seg" {
            self.viewControllerB = segue.destinationViewController as? ViewControllerB
        }
     }

     @IBAction func button(_ sender: AnyObject) {
         self.viewControllerB?.doSomethingWithHeight(newHeight)
     }
}



class ViewControllerB: UIViewController {

    @IBOutlet weak var childViewHeight: NSLayoutConstraint!

    func doSomethingWithHeight(newHeight: CGFloat) {
        self.childViewHeight.constant = newHeight
    }
}

这篇关于如何从父视图控制器多次传递数据到Swift中的VC孩子?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆