Truy cập UIViewContoder từ UIView?


185

Có một cách tích hợp để đi từ a UIViewđến nó UIViewControllerkhông? Tôi biết bạn có thể nhận được thông qua UIViewControllernó nhưng tôi đã tự hỏi nếu có một tài liệu tham khảo ngược?UIView[self view]

Câu trả lời:


46

Vì đây là câu trả lời được chấp nhận trong một thời gian dài, tôi cảm thấy mình cần khắc phục nó bằng một câu trả lời tốt hơn.

Một số ý kiến ​​về sự cần thiết:

  • Chế độ xem của bạn không cần phải truy cập trực tiếp vào bộ điều khiển xem.
  • Thay vào đó, khung nhìn phải độc lập với bộ điều khiển khung nhìn và có thể hoạt động trong các bối cảnh khác nhau.
  • Nếu bạn cần chế độ xem để giao diện theo cách với bộ điều khiển chế độ xem, cách được đề xuất và những gì Apple làm trên Cacao là sử dụng mẫu đại biểu.

Một ví dụ về cách thực hiện nó như sau:

@protocol MyViewDelegate < NSObject >

- (void)viewActionHappened;

@end

@interface MyView : UIView

@property (nonatomic, assign) MyViewDelegate delegate;

@end

@interface MyViewController < MyViewDelegate >

@end

Khung nhìn giao diện với đại biểu của nó ( UITableViewví dụ, chẳng hạn) và nó không quan tâm nếu nó được triển khai trong trình điều khiển khung nhìn hoặc trong bất kỳ lớp nào khác mà bạn kết thúc sử dụng.

Câu trả lời ban đầu của tôi như sau: Tôi không khuyến nghị điều này, cả những câu trả lời còn lại đều đạt được quyền truy cập trực tiếp vào bộ điều khiển xem

Không có cách tích hợp để làm điều đó. Mặc dù bạn có thể khắc phục bằng cách thêm IBOutletvào UIViewvà kết nối những thứ này trong Trình tạo giao diện, nhưng điều này không được khuyến khích. Chế độ xem không nên biết về bộ điều khiển xem. Thay vào đó, bạn nên làm như @Phil M gợi ý và tạo một giao thức được sử dụng làm đại biểu.


26
Đó là lời khuyên rất tồi. Bạn không nên tham khảo bộ điều khiển chế độ xem từ chế độ xem
Philippe Leybaert

6
@MattDiPasquale: vâng, đó là thiết kế tồi.
Philippe Leybaert

23
@Phillipe Leybaert Tôi tò mò muốn biết suy nghĩ của bạn về thiết kế tốt nhất cho sự kiện nhấn nút sẽ gọi một số hành động trên bộ điều khiển, mà không có chế độ xem tham chiếu đến bộ điều khiển. Cảm ơn
Jonathon Horsman

3
@PhilippeLeybaert Các dự án ví dụ của Apple có xu hướng thể hiện việc sử dụng các tính năng API cụ thể. Nhiều người tôi đã đề cập đến việc hy sinh thiết kế tốt hoặc có thể mở rộng để cung cấp một minh chứng ngắn gọn về chủ đề này. Phải mất một thời gian dài tôi mới nhận ra điều này và trong khi nó có ý nghĩa, tôi thấy thật đáng tiếc. Tôi nghĩ rằng rất nhiều nhà phát triển đã lấy những dự án thực dụng này làm hướng dẫn của Apple để thực hành thiết kế tốt nhất, điều mà tôi khá chắc chắn là không.
Stewohn

11
Tất cả bs này về "bạn không nên làm điều này" chỉ là vậy. Nếu một khung nhìn muốn biết về bộ điều khiển khung nhìn của nó, điều đó tùy thuộc vào người lập trình quyết định. giai đoạn = Stage.
Daniel Kanaan

203

Sử dụng ví dụ được đăng bởi Brock, tôi đã sửa đổi nó để nó là một thể loại của UIView thay vì UIViewControll và làm cho nó đệ quy để bất kỳ người xem phụ nào cũng có thể (hy vọng) tìm thấy UIViewControll gốc.

@interface UIView (FindUIViewController)
- (UIViewController *) firstAvailableUIViewController;
- (id) traverseResponderChainForUIViewController;
@end

@implementation UIView (FindUIViewController)
- (UIViewController *) firstAvailableUIViewController {
    // convenience function for casting and to "mask" the recursive function
    return (UIViewController *)[self traverseResponderChainForUIViewController];
}

- (id) traverseResponderChainForUIViewController {
    id nextResponder = [self nextResponder];
    if ([nextResponder isKindOfClass:[UIViewController class]]) {
        return nextResponder;
    } else if ([nextResponder isKindOfClass:[UIView class]]) {
        return [nextResponder traverseResponderChainForUIViewController];
    } else {
        return nil;
    }
}
@end

Để sử dụng mã này, hãy thêm nó vào một tệp lớp mới (tôi đặt tên là "UIKitC chuyên mục") và xóa dữ liệu lớp ... sao chép @interface vào tiêu đề và @im THỰCation vào tệp .m. Sau đó, trong dự án của bạn, #import "UIKitC loại.h" và sử dụng trong mã UIView:

// from a UIView subclass... returns nil if UIViewController not available
UIViewController * myController = [self firstAvailableUIViewController];

47
Và một lý do bạn cần cho phép UIView nhận thức được UIViewControll của nó là khi bạn có các lớp con UIView tùy chỉnh cần đẩy một chế độ xem / hộp thoại phương thức.
Phil M

Thật tuyệt vời, tôi đã phải truy cập vào ViewContoder của mình để hiển thị một cửa sổ bật lên tùy chỉnh được tạo bởi một
khung nhìn phụ

2
Đây có phải là một thực hành tồi đối với một UIView để thúc đẩy một cái nhìn phương thức không? Tôi đang làm điều này ngay bây giờ nhưng tôi cảm thấy đó không phải là điều nên làm ..
Van Du Tran

6
Phil, chế độ xem tùy chỉnh của bạn nên gọi một phương thức ủy nhiệm mà trình điều khiển chế độ xem lắng nghe và sau đó nó sẽ đẩy từ đó.
malhal

9
Tôi chỉ thích có bao nhiêu câu hỏi SO đã có một "người thông thái", học thuật, câu trả lời được chấp nhận chỉ với một vài điểm và câu trả lời thứ hai thực tế, bẩn thỉu và trái với quy tắc, với mười lần điểm :-)
hariseldon78

114

UIViewlà một lớp con của UIResponder. UIResponderđưa ra phương thức -nextRespondervới việc thực hiện trả về nil. UIViewghi đè phương thức này, như được ghi lại trong UIResponder(vì một số lý do thay vì in UIView) như sau: nếu chế độ xem có bộ điều khiển xem, nó được trả về bởi-nextResponder . Nếu không có trình điều khiển xem, phương thức sẽ trả về giám sát.

Thêm điều này vào dự án của bạn và bạn đã sẵn sàng để tung ra.

@interface UIView (APIFix)
- (UIViewController *)viewController;
@end

@implementation UIView (APIFix)

- (UIViewController *)viewController {
    if ([self.nextResponder isKindOfClass:UIViewController.class])
        return (UIViewController *)self.nextResponder;
    else
        return nil;
}
@end

Bây giờ UIViewcó một phương thức làm việc để trả về bộ điều khiển xem.


5
Điều này sẽ chỉ hoạt động nếu không có gì trong chuỗi phản hồi giữa nhận UIViewUIViewController. Câu trả lời của Phil M có tính đệ quy là con đường để đi.
Olivier

33

Tôi sẽ đề xuất một cách tiếp cận nhẹ nhàng hơn để vượt qua chuỗi phản hồi hoàn chỉnh mà không cần phải thêm một danh mục trên UIView:

@implementation MyUIViewSubclass

- (UIViewController *)viewController {
    UIResponder *responder = self;
    while (![responder isKindOfClass:[UIViewController class]]) {
        responder = [responder nextResponder];
        if (nil == responder) {
            break;
        }
    }
    return (UIViewController *)responder;
}

@end

22

Kết hợp một số câu trả lời đã được đưa ra, tôi cũng đang thực hiện nó với việc thực hiện:

@implementation UIView (AppNameAdditions)

- (UIViewController *)appName_viewController {
    /// Finds the view's view controller.

    // Take the view controller class object here and avoid sending the same message iteratively unnecessarily.
    Class vcc = [UIViewController class];

    // Traverse responder chain. Return first found view controller, which will be the view's view controller.
    UIResponder *responder = self;
    while ((responder = [responder nextResponder]))
        if ([responder isKindOfClass: vcc])
            return (UIViewController *)responder;

    // If the view controller isn't found, return nil.
    return nil;
}

@end

Danh mục này là một phần của thư viện tĩnh hỗ trợ ARC mà tôi gửi trên mọi ứng dụng tôi tạo. Nó đã được thử nghiệm nhiều lần và tôi không tìm thấy bất kỳ vấn đề hoặc rò rỉ nào.

Tái bút: Bạn không cần sử dụng danh mục như tôi đã làm nếu chế độ xem liên quan là lớp con của bạn. Trong trường hợp sau, chỉ cần đặt phương thức vào lớp con của bạn và bạn sẽ ổn.


1
Đây là câu trả lời tốt nhất. Không cần đệ quy, phiên bản này được tối ưu hóa độc đáo
zeroimpl

12

Mặc dù điều này về mặt kỹ thuật có thể được giải quyết như pgb khuyến nghị, IMHO, đây là một lỗ hổng thiết kế. Khung nhìn không cần phải biết về bộ điều khiển.


Tôi chỉ không chắc làm thế nào mà viewContoder có thể được nói rằng một trong những view của nó sẽ biến mất và nó cần gọi một trong các phương thức viewXXXAppear / viewXXXDisappear của nó.
mahboudz

2
Đây là ý tưởng đằng sau mẫu Observer. Người quan sát (Chế độ xem trong trường hợp này) không nên biết trực tiếp Người quan sát của mình. Người quan sát chỉ nên nhận các cuộc gọi lại mà họ quan tâm.
Ushox

12

Tôi sửa đổi de câu trả lời để tôi có thể vượt qua bất kỳ quan điểm, nút, nhãn vv để có được nó của cha mẹ UIViewController. Đây là mã của tôi.

+(UIViewController *)viewController:(id)view {
    UIResponder *responder = view;
    while (![responder isKindOfClass:[UIViewController class]]) {
        responder = [responder nextResponder];
        if (nil == responder) {
            break;
        }
    }
    return (UIViewController *)responder;
}

Chỉnh sửa phiên bản Swift 3

class func viewController(_ view: UIView) -> UIViewController {
        var responder: UIResponder? = view
        while !(responder is UIViewController) {
            responder = responder?.next
            if nil == responder {
                break
            }
        }
        return (responder as? UIViewController)!
    }

Chỉnh sửa 2: - Mở rộng Swift

extension UIView
{
    //Get Parent View Controller from any view
    func parentViewController() -> UIViewController {
        var responder: UIResponder? = self
        while !(responder is UIViewController) {
            responder = responder?.next
            if nil == responder {
                break
            }
        }
        return (responder as? UIViewController)!
    }
}

7

Đừng quên rằng bạn có thể truy cập vào bộ điều khiển xem gốc cho cửa sổ mà chế độ xem là một khung nhìn phụ. Từ đó, nếu bạn đang sử dụng bộ điều khiển chế độ xem điều hướng và muốn đẩy chế độ xem mới lên nó:

    [[[[self window] rootViewController] navigationController] pushViewController:newController animated:YES];

Tuy nhiên, trước tiên bạn cần phải thiết lập thuộc tính rootViewControll của cửa sổ. Làm điều này khi bạn lần đầu tiên tạo bộ điều khiển, ví dụ như trong đại biểu ứng dụng của bạn:

-(void) applicationDidFinishLaunching:(UIApplication *)application {
    window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    RootViewController *controller = [[YourRootViewController] alloc] init];
    [window setRootViewController: controller];
    navigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
    [controller release];
    [window addSubview:[[self navigationController] view]];
    [window makeKeyAndVisible];
}

Dường như với tôi, theo tài liệu của Apple[[self navigationController] view]là chế độ xem "chính" (phụ) của cửa sổ, thuộc rootViewControllertính của cửa sổ phải được đặt thành navigationControllerđiều khiển chế độ xem "chính" ngay lập tức.
adubr

6

Mặc dù các câu trả lời này là đúng về mặt kỹ thuật, bao gồm Ushox, tôi nghĩ cách được phê duyệt là thực hiện một giao thức mới hoặc sử dụng lại một giao thức hiện có. Một giao thức cách ly người quan sát khỏi quan sát, giống như đặt một khe thư ở giữa chúng. Trong thực tế, đó là những gì Gabriel làm thông qua việc gọi phương thức PushViewControll; Chế độ xem "biết" rằng đó là giao thức thích hợp để yêu cầu một cách lịch sự điều hướng của bạn để điều khiển một khung nhìn, vì viewContoder tuân thủ giao thức navigationContoder. Mặc dù bạn có thể tạo giao thức của riêng mình, chỉ cần sử dụng ví dụ của Gabriel và sử dụng lại giao thức UINavestionControll là tốt.


6

Tôi tình cờ thấy một tình huống mà tôi có một thành phần nhỏ mà tôi muốn sử dụng lại và đã thêm một số mã trong chế độ xem có thể sử dụng lại (nó thực sự không khác gì một nút mở a PopoverController).

Mặc dù điều này hoạt động tốt trong iPad ( UIPopoverControllerbản thân quà tặng, do đó không cần tham chiếu đến a UIViewController), nhưng việc sử dụng cùng một mã có nghĩa là đột nhiên tham chiếu presentViewControllertừ bạn UIViewController. Kinda không nhất quán phải không?

Giống như đã đề cập trước đây, đây không phải là cách tiếp cận tốt nhất để có logic trong UIView của bạn. Nhưng nó cảm thấy thực sự vô dụng khi bọc một vài dòng mã cần thiết trong một bộ điều khiển riêng.

Dù bằng cách nào, đây là một giải pháp nhanh chóng, bổ sung một thuộc tính mới cho bất kỳ UIView nào:

extension UIView {

    var viewController: UIViewController? {

        var responder: UIResponder? = self

        while responder != nil {

            if let responder = responder as? UIViewController {
                return responder
            }
            responder = responder?.nextResponder()
        }
        return nil
    }
}

5

Tôi không nghĩ rằng đó là ý tưởng "xấu" để tìm ra ai là người điều khiển chế độ xem cho một số trường hợp. Điều có thể là một ý tưởng tồi là lưu tham chiếu đến bộ điều khiển này vì nó có thể thay đổi khi giám sát thay đổi. Trong trường hợp của tôi, tôi có một getter đi qua chuỗi phản hồi.

//.h

@property (nonatomic, readonly) UIViewController * viewController;

//

- (UIViewController *)viewController
{
    for (UIResponder * nextResponder = self.nextResponder;
         nextResponder;
         nextResponder = nextResponder.nextResponder)
    {
        if ([nextResponder isKindOfClass:[UIViewController class]])
            return (UIViewController *)nextResponder;
    }

    // Not found
    NSLog(@"%@ doesn't seem to have a viewController". self);
    return nil;
}

4

Vòng lặp do đơn giản nhất để tìm viewContoder.

-(UIViewController*)viewController
{
    UIResponder *nextResponder =  self;

    do
    {
        nextResponder = [nextResponder nextResponder];

        if ([nextResponder isKindOfClass:[UIViewController class]])
            return (UIViewController*)nextResponder;

    } while (nextResponder != nil);

    return nil;
}

4

Swift 4

(ngắn gọn hơn các câu trả lời khác)

fileprivate extension UIView {

  var firstViewController: UIViewController? {
    let firstViewController = sequence(first: self, next: { $0.next }).first(where: { $0 is UIViewController })
    return firstViewController as? UIViewController
  }

}

Trường hợp sử dụng của tôi mà tôi cần truy cập vào chế độ xem trước UIViewController: Tôi có một đối tượng bao quanh AVPlayer/ AVPlayerViewControllervà tôi muốn cung cấp một show(in view: UIView)phương thức đơn giản sẽ nhúng AVPlayerViewControllervào view. Cho rằng, tôi cần phải truy cập view's UIViewController.


3

Điều này không trả lời trực tiếp câu hỏi, mà là đưa ra một giả định về ý định của câu hỏi.

Nếu bạn có chế độ xem và trong chế độ xem đó, bạn cần gọi một phương thức trên một đối tượng khác, như nói bộ điều khiển chế độ xem, bạn có thể sử dụng NSNotificationCenter thay thế.

Đầu tiên tạo chuỗi thông báo của bạn trong tệp tiêu đề

#define SLCopyStringNotification @"ShaoloCopyStringNotification"

Theo quan điểm của bạn, hãy gọi postNotificationName:

- (IBAction) copyString:(id)sender
{
    [[NSNotificationCenter defaultCenter] postNotificationName:SLCopyStringNotification object:nil];
}

Sau đó, trong trình điều khiển xem của bạn, bạn thêm một người quan sát. Tôi làm điều này trong viewDidLoad

- (void)viewDidLoad
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(copyString:)
                                                 name:SLCopyStringNotification
                                               object:nil];
}

Bây giờ (cũng trong cùng một trình điều khiển khung nhìn) triển khai phương thức copyString của bạn: như được mô tả trong @selector ở trên.

- (IBAction) copyString:(id)sender
{
    CalculatorResult* result = (CalculatorResult*)[[PercentCalculator sharedInstance].arrayTableDS objectAtIndex:([self.viewTableResults indexPathForSelectedRow].row)];
    UIPasteboard *gpBoard = [UIPasteboard generalPasteboard];
    [gpBoard setString:result.stringResult];
}

Tôi không nói rằng đây là cách đúng đắn để làm điều này, nó chỉ có vẻ sạch hơn so với việc chạy chuỗi phản hồi đầu tiên. Tôi đã sử dụng mã này để triển khai UIMothyContoder trên UITableView và chuyển sự kiện trở lại cho UIViewContoder để tôi có thể làm gì đó với dữ liệu.


3

Đó chắc chắn là một ý tưởng tồi và một thiết kế sai, nhưng tôi chắc chắn tất cả chúng ta đều có thể tận hưởng một giải pháp Swift cho câu trả lời tốt nhất được đề xuất bởi @Phil_M:

static func firstAvailableUIViewController(fromResponder responder: UIResponder) -> UIViewController? {
    func traverseResponderChainForUIViewController(responder: UIResponder) -> UIViewController? {
        if let nextResponder = responder.nextResponder() {
            if let nextResp = nextResponder as? UIViewController {
                return nextResp
            } else {
                return traverseResponderChainForUIViewController(nextResponder)
            }
        }
        return nil
    }

    return traverseResponderChainForUIViewController(responder)
}

Nếu ý định của bạn là làm những việc đơn giản, như hiển thị hộp thoại theo chế độ hoặc dữ liệu theo dõi, điều đó không biện minh cho việc sử dụng giao thức. Cá nhân tôi lưu trữ chức năng này trong một đối tượng tiện ích, bạn có thể sử dụng nó từ bất cứ thứ gì thực hiện giao thức UIResponder như:

if let viewController = MyUtilityClass.firstAvailableUIViewController(self) {}

Tất cả tín dụng cho @Phil_M


3

Có lẽ tôi đến muộn. Nhưng trong tình huống này tôi không thích thể loại (ô nhiễm). Tôi thích cách này:

#define UIViewParentController(__view) ({ \
UIResponder *__responder = __view; \
while ([__responder isKindOfClass:[UIView class]]) \
__responder = [__responder nextResponder]; \
(UIViewController *)__responder; \
})

3

Giải pháp nhanh hơn

extension UIView {
    var parentViewController: UIViewController? {
        for responder in sequence(first: self, next: { $0.next }) {
            if let viewController = responder as? UIViewController {
                return viewController
            }
        }
        return nil
    }
}

Tôi thích câu trả lời này. Tôi không chắc chắn rằng nó nhiều hơn mặc dù. Swift là một ngôn ngữ khác không thể quyết định mà sẽ kết hôn với các ngôn ngữ. Trong trường hợp này, bạn có một minh chứng hay về cách tiếp cận nhiều chức năng hơn ( sequencebit). Vì vậy, nếu "swifty" có nghĩa là "nhiều chức năng hơn", thì tôi đoán nó sẽ tiện lợi hơn.
Travis Griggs

2

Phiên bản cập nhật cho swift 4: Cảm ơn @Phil_M và @ paul-slm

static func firstAvailableUIViewController(fromResponder responder: UIResponder) -> UIViewController? {
    func traverseResponderChainForUIViewController(responder: UIResponder) -> UIViewController? {
        if let nextResponder = responder.next {
            if let nextResp = nextResponder as? UIViewController {
                return nextResp
            } else {
                return traverseResponderChainForUIViewController(responder: nextResponder)
            }
        }
        return nil
    }

    return traverseResponderChainForUIViewController(responder: responder)
}

2

Phiên bản Swift 4

extension UIView {
var parentViewController: UIViewController? {
    var parentResponder: UIResponder? = self
    while parentResponder != nil {
        parentResponder = parentResponder!.next
        if let viewController = parentResponder as? UIViewController {
            return viewController
        }
    }
    return nil
}

Ví dụ sử dụng

 if let parent = self.view.parentViewController{

 }

2

Hai giải pháp kể từ Swift 5.2 :

  • Thêm về mặt chức năng
  • Không cần returntừ khóa ngay bây giờ

Giải pháp 1:

extension UIView {
    var parentViewController: UIViewController? {
        sequence(first: self) { $0.next }
            .first(where: { $0 is UIViewController })
            .flatMap { $0 as? UIViewController }
    }
}

Giải pháp 2:

extension UIView {
    var parentViewController: UIViewController? {
        sequence(first: self) { $0.next }
            .compactMap{ $0 as? UIViewController }
            .first
    }
}
  • Giải pháp này yêu cầu lặp qua từng lần phản hồi trước, vì vậy có thể không phải là hiệu suất cao nhất.

1

Để trả lời của Phil:

Trong dòng: id nextResponder = [self nextResponder]; nếu self (UIView) không phải là một khung nhìn phụ của khung nhìn ViewContoder, nếu bạn biết thứ bậc của bản thân (UIView), bạn cũng có thể sử dụng: id nextResponder = [[self superview] nextResponder];...


0

Giải pháp của tôi có thể được coi là không có thật nhưng tôi cũng gặp tình huống tương tự như mayoneez (tôi muốn chuyển đổi chế độ xem theo cử chỉ trong EAGLView) và tôi đã sử dụng trình điều khiển chế độ xem của EAGL theo cách này:

EAGLViewController *vc = ((EAGLAppDelegate*)[[UIApplication sharedApplication] delegate]).viewController;

2
Vui lòng viết lại mã của bạn như sau : EAGLViewController *vc = [(EAGLAppDelegate *)[UIApplication sharedApplication].delegate viewController];.
Jonathan Sterling

1
Vấn đề không phải là cú pháp dấu chấm, mà là với các loại. Trong Mục tiêu C để khai báo một đối tượng bạn viết ClassName *object- bằng dấu hoa thị.
adubr

Rất tiếc ... đó thực sự là những gì tôi đã có, nhưng tiện ích HTML StackOverflow trông có vẻ như nó nghĩ dấu hoa thị có nghĩa là chữ nghiêng ... Tôi đã thay đổi nó thành một khối mã, bây giờ nó hiển thị chính xác. Cảm ơn!
gulchrider

0

Tôi nghĩ rằng có một trường hợp khi quan sát cần phải thông báo cho người quan sát.

Tôi thấy một vấn đề tương tự trong đó UIView trong UIViewContoder đang phản ứng với một tình huống và trước tiên nó cần nói với bộ điều khiển khung nhìn cha mẹ của nó để ẩn nút quay lại và sau khi hoàn thành, hãy nói với bộ điều khiển khung nhìn cha mẹ rằng nó cần tự bật ra khỏi ngăn xếp.

Tôi đã thử điều này với các đại biểu không có thành công.

Tôi không hiểu tại sao điều này nên là một ý tưởng tồi?


0

Một cách dễ dàng khác là có lớp khung nhìn của riêng bạn và thêm một thuộc tính của trình điều khiển khung nhìn trong lớp khung nhìn. Thông thường bộ điều khiển khung nhìn tạo ra khung nhìn và đó là nơi bộ điều khiển có thể tự đặt thành thuộc tính. Về cơ bản, nó thay vì tìm kiếm xung quanh (với một chút hack) cho bộ điều khiển, có bộ điều khiển để tự đặt chế độ xem - điều này đơn giản nhưng có ý nghĩa vì nó là bộ điều khiển "điều khiển" chế độ xem.


0

Nếu bạn không tải nó lên App Store, bạn cũng có thể sử dụng phương pháp riêng tư của UIView.

@interface UIView(Private)
- (UIViewController *)_viewControllerForAncestor;
@end

// Later in the code
UIViewController *vc = [myView _viewControllerForAncestor];

0
var parentViewController: UIViewController? {
    let s = sequence(first: self) { $0.next }
    return s.compactMap { $0 as? UIViewController }.first
}

Mặc dù mã này có thể trả lời câu hỏi, một câu trả lời tốt cũng sẽ giải thích mã đó làm gì và cách giải quyết vấn đề.
BDL

0

Để có được bộ điều khiển của một khung nhìn nhất định, người ta có thể sử dụng chuỗi UIFirstResponder.

customView.target(forAction: Selector("viewDidLoad"), withSender: nil)

-1

Nếu rootViewControll của bạn là UINavlationViewContaptor, được thiết lập trong lớp AppDelegate, thì

    + (UIViewController *) getNearestViewController:(Class) c {
NSArray *arrVc = [[[[UIApplication sharedApplication] keyWindow] rootViewController] childViewControllers];

for (UIViewController *v in arrVc)
{
    if ([v isKindOfClass:c])
    {
        return v;
    }
}

return nil;}

Trường hợp c yêu cầu xem lớp điều khiển.

SỬ DỤNG:

     RequiredViewController* rvc = [Utilities getNearestViewController:[RequiredViewController class]];

-5

Không có cách nào.

Những gì tôi làm là chuyển con trỏ UIViewControll sang UIView (hoặc một kế thừa thích hợp). Tôi xin lỗi tôi không thể giúp đỡ với cách tiếp cận IB đối với vấn đề này vì tôi không tin vào IB.

Để trả lời người bình luận đầu tiên: đôi khi bạn cần biết ai đã gọi bạn vì nó quyết định bạn có thể làm gì. Ví dụ: với cơ sở dữ liệu, bạn có thể chỉ có quyền truy cập đọc hoặc đọc / ghi ...


10
Điều đó có nghĩa là gì - "Tôi không tin vào IB"? Tôi đã đưa ra nó, nó chắc chắn tồn tại.
marcc

5
Bạn cần nắm bắt tốt hơn niềm vui và sự trừu tượng, đặc biệt là liên quan đến ngôn ngữ tiếng Anh. Nó có nghĩa là tôi không thích nó.
John Smith

4
Tôi không thích bơ. Nhưng tôi cá là tôi có thể giúp ai đó làm guacamole. Nó có thể được thực hiện trong IB, vì vậy rõ ràng câu trả lời của bạn về "không có cách nào" là không chính xác. Cho dù bạn có thích IB hay không thì không liên quan.
Mèo Feloneous
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.