在 iOS6 中,我注意到新的容器视图,但不太确定如何从包含视图访问它的控制器。
设想:
我想从包含容器视图的视图控制器访问警报视图控制器中的标签。
他们之间有一个segue,我可以使用它吗?
在 iOS6 中,我注意到新的容器视图,但不太确定如何从包含视图访问它的控制器。
设想:
我想从包含容器视图的视图控制器访问警报视图控制器中的标签。
他们之间有一个segue,我可以使用它吗?
是的,您可以使用 segue 访问子视图控制器(及其视图和子视图)。alertview_embed
使用 Storyboard 中的属性检查器给 segue 一个标识符(例如)。然后让父视图控制器(包含容器视图的那个)实现如下方法:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSString * segueName = segue.identifier;
if ([segueName isEqualToString: @"alertview_embed"]) {
AlertViewController * childViewController = (AlertViewController *) [segue destinationViewController];
AlertView * alertView = childViewController.view;
// do something with the AlertView's subviews here...
}
}
您可以简单地使用self.childViewControllers.lastObject
(假设您只有一个孩子,否则使用objectAtIndex:
)。
用于 Swift 编程
你可以这样写
var containerViewController: ExampleViewController?
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// you can set this name in 'segue.embed' in storyboard
if segue.identifier == "checkinPopupIdentifierInStoryBoard" {
let connectContainerViewController = segue.destinationViewController as ExampleViewController
containerViewController = connectContainerViewController
}
}
该prepareForSegue
方法有效,但它依赖于 segue 标识符魔术字符串。也许有更好的方法。
如果您知道您所追求的 VC 的类,您可以使用计算属性非常巧妙地做到这一点:
var camperVan: CamperVanViewController? {
return childViewControllers.flatMap({ $0 as? CamperVanViewController }).first
// This works because `flatMap` removes nils
}
这依赖于childViewControllers
. 虽然我同意依赖第一个可能很脆弱,但命名您所寻求的类会使这看起来很可靠。
Swift 3 的更新答案,使用计算属性:
var jobSummaryViewController: JobSummaryViewController {
get {
let ctrl = childViewControllers.first(where: { $0 is JobSummaryViewController })
return ctrl as! JobSummaryViewController
}
}
这只会迭代子列表,直到它到达第一个匹配项。
self.childViewControllers
当您需要来自父母的控制时,它更相关。例如,如果子控制器是一个表格视图,并且您想强制重新加载它或通过按钮点击或父视图控制器上的任何其他事件更改属性,您可以通过访问 ChildViewController 的实例而不是通过 prepareForSegue 来实现。两者都有不同的应用方式。
在视图控制器的类型上使用 Swift 的 switch 语句还有另一种方法:
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
switch segue.destination
{
case let aViewController as AViewController:
self.aViewController = aViewController
case let bViewController as BViewController:
self.bViewController = bViewController
default:
return
}
}
我使用如下代码:
- (IBAction)showCartItems:(id)sender{
ListOfCartItemsViewController *listOfItemsVC=[self.storyboard instantiateViewControllerWithIdentifier:@"ListOfCartItemsViewController"];
[self addChildViewController:listOfItemsVC];
}
如果有人正在寻找Swift 3.0,
viewController1,viewController2等将可以访问。
let viewController1 : OneViewController!
let viewController2 : TwoViewController!
// Safety handling of optional String
if let identifier: String = segue.identifier {
switch identifier {
case "segueName1":
viewController1 = segue.destination as! OneViewController
break
case "segueName2":
viewController2 = segue.destination as! TwoViewController
break
// ... More cases can be inserted here ...
default:
// A new segue is added in the storyboard but not yet including in this switch
print("A case missing for segue identifier: \(identifier)")
break
}
} else {
// Either the segue or the identifier is inaccessible
print("WARNING: identifier in segue is not accessible")
}
使用泛型你可以做一些甜蜜的事情。这是 Array 的扩展:
extension Array {
func firstMatchingType<Type>() -> Type? {
return first(where: { $0 is Type }) as? Type
}
}
然后,您可以在 viewController 中执行此操作:
var viewControllerInContainer: YourViewControllerClass? {
return childViewControllers.firstMatchingType()!
}
你可以这样写
- (IBAction)showDetail:(UIButton *)sender {
DetailViewController *detailVc = [self.childViewControllers firstObject];
detailVc.lable.text = sender.titleLabel.text;
}
}