へのポインタがありますUIView
。その にはどうやってアクセスするのでしょうかUIViewController
?[self superview]
は別の でありUIView
、 ではないですUIViewController
よね?
ベストアンサー1
UIResponder
のドキュメントよりnextResponder
:
UIResponder クラスは、次のレスポンダーを自動的に保存または設定せず、代わりにデフォルトで nil を返します。サブクラスは、次のレスポンダーを設定するためにこのメソッドをオーバーライドする必要があります。UIView は、それを管理する UIViewController オブジェクト (存在する場合) またはそのスーパービュー (存在しない場合) を返すことによってこのメソッドを実装します。; UIViewController はビューのスーパービューを返すことによってメソッドを実装します。UIWindow はアプリケーション オブジェクトを返し、UIApplication は nil を返します。
したがって、ビューがnextResponder
タイプになるまで を再帰するとUIViewController
、任意のビューの親 viewController が得られます。
ただし、ない親ビューコントローラがあります。ただし、ビューが viewController のビューのビュー階層の一部ではない場合に限ります。
Swift 3とスウィフト4.1拡大:
extension UIView {
var parentViewController: UIViewController? {
// Starts from next (As we know self is not a UIViewController).
var parentResponder: UIResponder? = self.next
while parentResponder != nil {
if let viewController = parentResponder as? UIViewController {
return viewController
}
parentResponder = parentResponder?.next
}
return nil
}
}
Swift 2 拡張機能:
extension UIView {
var parentViewController: UIViewController? {
var parentResponder: UIResponder? = self.nextResponder()
while parentResponder != nil {
if let viewController = parentResponder as? UIViewController {
return viewController
}
parentResponder = parentResponder!.nextResponder()
}
return nil
}
}
Objective-C カテゴリ:
@interface UIView (mxcl)
- (UIViewController *)parentViewController;
@end
@implementation UIView (mxcl)
- (UIViewController *)parentViewController {
UIResponder *responder = [self nextResponder];
while (responder != nil) {
if ([responder isKindOfClass:[UIViewController class]]) {
return (UIViewController *)responder;
}
responder = [responder nextResponder];
}
return nil;
}
@end
このマクロはカテゴリ汚染を回避します:
#define UIViewParentController(__view) ({ \
UIResponder *__responder = __view; \
while ([__responder isKindOfClass:[UIView class]]) \
__responder = [__responder nextResponder]; \
(UIViewController *)__responder; \
})