如何从 class 本身中初始化自定义视图控制器?

How do I initialize a custom view controller from within the class itself?

我正在尝试使用第三方库 MBPullDownController 制作类似 Google 地图应用中的向上滑动面板的东西。

这是库中的示例代码:

UITableViewController *front = [[UITableViewController new];
UIViewController *back = [[UIViewController new];
MBPullDownController *pullDownController = [[MBPullDownController alloc] initWithFrontController:front backController:back];
[self.navigationController pushViewController:pullDownController animated:NO];

从不同的视图控制器导航到它时工作正常。但是我的地图控制器有四五个其他视图控制器直接指向它,所以我尝试从地图控制器本身进行初始化。

我试过使我的视图控制器成为 MBPullDownController 的子类,并尝试在 initUsingCoder: 方法中初始化它,如下所示:

MapViewController.h

#import <UIKit/UIKit.h>
#import <GoogleMaps/GoogleMaps.h>
#import "MBPullDownController.h"
....

@interface MapViewController : MBPullDownController<GMSMapViewDelegate>
....
@end

MapViewController.m

#import "MapViewController.h"
#import <GoogleMaps/GoogleMaps.h>
#import "LocationUtility.h"
#import "MBPullDownController.h"
...

@interface MapViewController () <CLLocationManagerDelegate>
@property (strong, nonatomic) CLLocationManager *locationManager;
@end

@implementation MapViewController {
    GMSMapView *mapView;
    NSMutableDictionary *markers;
}

@implementation MapViewController {
GMSMapView *mapView;
NSMutableDictionary *markers;
UITableViewController *front;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        front = [UITableViewController new];
        self = (MapViewController *)[[MBPullDownController alloc]initWithFrontController:front backController:self ];
    }
    return self;
}
....

我收到警告 'This coder requires that replaced objects be returned from initWithCoder:',显然是因为 self = [super initWithCoder:aDecoder]self = (MapViewController *)[[MBPullDownController alloc]initWithFrontController:front backController:self ];

取代了

如何正确地将视图控制器初始化为 MBPullDownController 本身?

实际上我在写问题的过程中找到了解决方案,但我想我会坚持下去以帮助其他遇到同样问题的人,因为答案并不容易找到。

解决方法是使用-(id)awakeAfterUsingCoder:(NSCoder *)aDecoder方法,即"allows you to substitute another object in place of the object that was decoded" (source).

- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder
{
    if (self) {
        front = [UITableViewController new];
        self = (MapViewController *)[[MBPullDownController alloc]initWithFrontController:front backController:self ];
    }
    return self;
}

问题是您正在尝试使用初始化器 initWithFrontController.. 而不是 initWithCoder 来初始化 MBPullDownController 的实例,这是 iOS 在从 nib 实例化对象时强制您调用的那个。

该库应该有另一个名为 initWithCoder: andFrontController: andBackController 的方法,负责调用 super 并正确设置子控制器。

但是,由于没有提供,创建者似乎同时设置了 frontController 和 backController public。这通常(如果他做得好)意味着您可以在调用 initializr 后随意设置这些属性。所以我会尝试:

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        self.frontController = [UITableViewController new];
        self.backController = self;
    }
    return self;  
}

如果这不起作用,您应该在 github 中创建一个问题并告诉创建者添加 initWithCoder 初始值设定项,并使用 awakeAfterUsingCoder

保持您的解决方案