Cách sử dụng uiviewcontroller bảng phân cảnh duy nhất cho nhiều lớp con


118

Giả sử tôi có một bảng phân cảnh chứa UINavigationControllerdưới dạng bộ điều khiển chế độ xem ban đầu. Bộ điều khiển chế độ xem gốc của nó là lớp con của UITableViewControllerBasicViewController. Nó có IBActionđược kết nối với nút điều hướng bên phải của thanh điều hướng

Từ đó tôi muốn sử dụng bảng phân cảnh làm mẫu cho các chế độ xem khác mà không cần phải tạo thêm bảng phân cảnh. Giả sử các khung nhìn này sẽ có cùng một giao diện nhưng với bộ điều khiển chế độ xem gốc của lớp SpecificViewController1SpecificViewController2là các lớp con của BasicViewController.
2 bộ điều khiển chế độ xem đó sẽ có cùng chức năng và giao diện ngoại trừ IBActionphương thức.
Nó sẽ giống như sau:

@interface BasicViewController : UITableViewController

@interface SpecificViewController1 : BasicViewController

@interface SpecificViewController2 : BasicViewController

Tôi có thể làm một cái gì đó như vậy?
Tôi có thể chỉ khởi tạo bảng phân cảnh của BasicViewControllernhưng có bộ điều khiển chế độ xem gốc vào lớp con SpecificViewController1SpecificViewController2?

Cảm ơn.


3
Có thể đáng để chỉ ra rằng bạn có thể làm điều này với ngòi. Nhưng nếu bạn giống như tôi, người muốn một số tính năng hay mà chỉ có bảng phân cảnh mới có (ví dụ: ô tĩnh / nguyên mẫu), thì tôi đoán chúng ta đã gặp may.
Joseph Lin

Câu trả lời:


57

câu hỏi tuyệt vời - nhưng tiếc là chỉ có một câu trả lời khập khiễng. Tôi không tin rằng hiện tại có thể làm những gì bạn đề xuất vì không có trình khởi tạo nào trong UIStoryboard cho phép ghi đè bộ điều khiển chế độ xem được liên kết với bảng phân cảnh như được xác định trong chi tiết đối tượng trong bảng phân cảnh khi khởi chạy. Lúc khởi tạo, tất cả các phần tử giao diện người dùng trong bảng xếp hạng được liên kết với các thuộc tính của chúng trong bộ điều khiển chế độ xem.

Theo mặc định, nó sẽ khởi tạo với bộ điều khiển chế độ xem được chỉ định trong định nghĩa bảng phân cảnh.

Nếu bạn đang cố gắng sử dụng lại các phần tử giao diện người dùng mà bạn đã tạo trong bảng phân cảnh, chúng vẫn phải được liên kết hoặc liên kết với các thuộc tính mà bộ điều khiển chế độ xem đang sử dụng chúng để chúng có thể "nói" với bộ điều khiển chế độ xem về các sự kiện.

Việc sao chép bố cục bảng phân cảnh không phải là vấn đề lớn, đặc biệt nếu bạn chỉ cần một thiết kế tương tự cho 3 chế độ xem, tuy nhiên nếu làm vậy, bạn phải đảm bảo rằng tất cả các liên kết trước đó đã được xóa, nếu không nó sẽ bị treo khi cố gắng để giao tiếp với bộ điều khiển chế độ xem trước đó. Bạn sẽ có thể nhận ra chúng dưới dạng thông báo lỗi KVO trong đầu ra nhật ký.

Một số cách tiếp cận bạn có thể thực hiện:

  • lưu trữ các phần tử giao diện người dùng trong một UIView - trong tệp xib và khởi tạo nó từ lớp cơ sở của bạn và thêm nó làm chế độ xem phụ trong chế độ xem chính, thường là self.view. Sau đó, bạn chỉ cần sử dụng bố cục bảng phân cảnh với các bộ điều khiển chế độ xem trống về cơ bản giữ vị trí của chúng trong bảng phân cảnh nhưng với lớp con bộ điều khiển chế độ xem chính xác được chỉ định cho chúng. Vì họ sẽ kế thừa từ cơ sở, họ sẽ có được quan điểm đó.

  • tạo bố cục trong mã và cài đặt nó từ bộ điều khiển chế độ xem cơ sở của bạn. Rõ ràng cách tiếp cận này đánh bại mục đích của việc sử dụng bảng phân cảnh, nhưng có thể là cách tốt nhất trong trường hợp của bạn. Nếu bạn có các phần khác của ứng dụng sẽ được hưởng lợi từ cách tiếp cận bảng phân cảnh, bạn có thể điều chỉnh ở đây và ở đó nếu thích hợp. Trong trường hợp này, giống như trên, bạn sẽ chỉ sử dụng bộ điều khiển chế độ xem ngân hàng với lớp con của bạn được chỉ định và để bộ điều khiển chế độ xem cơ sở cài đặt giao diện người dùng.

Sẽ rất tuyệt nếu Apple nghĩ ra một cách để thực hiện những gì bạn đề xuất, nhưng vấn đề có các yếu tố đồ họa được liên kết trước với lớp con bộ điều khiển vẫn sẽ là một vấn đề.

Chúc mừng năm mới!! mạnh giỏi nhé


Nó thật nhanh. Như tôi nghĩ, nó sẽ không thể được. Hiện tại, tôi đưa ra một giải pháp bằng cách chỉ có lớp BasicViewController đó và có thêm thuộc tính để cho biết nó sẽ hoạt động như "lớp" / "chế độ" nào. Dẫu sao cũng xin cảm ơn.
xanh tươi

2
quá tệ :( Đoán là tôi phải sao chép và dán cùng một bộ điều khiển chế độ xem và thay đổi lớp của nó như một giải pháp thay thế.
Hlung

1
Và đây là lý do tại sao tôi không thích Bảng phân cảnh ... bằng cách nào đó chúng không thực sự hoạt động một khi bạn làm nhiều hơn một chút so với chế độ xem tiêu chuẩn ...
TheEye

Thật buồn khi nghe bạn nói vậy. Tôi đang tìm giải pháp
Tony

2
Có một cách tiếp cận khác: Chỉ định logic tùy chỉnh trong các đại biểu khác nhau và trong readyForSegue, chỉ định đại biểu chính xác. Bằng cách này, bạn tạo 1 UIViewController + 1 UIViewController trong Storyboard nhưng bạn có nhiều phiên bản triển khai.
plam4u

45

Mã dòng chúng tôi đang tìm kiếm là:

object_setClass(AnyObject!, AnyClass!)

Trong Storyboard -> thêm UIViewController, đặt tên lớp ParentVC.

class ParentVC: UIViewController {

    var type: Int?

    override func awakeFromNib() {

        if type = 0 {

            object_setClass(self, ChildVC1.self)
        }
        if type = 1 {

            object_setClass(self, ChildVC2.self)
        }  
    }

    override func viewDidLoad() {   }
}

class ChildVC1: ParentVC {

    override func viewDidLoad() {
        super.viewDidLoad()

        println(type)
        // Console prints out 0
    }
}

class ChildVC2: ParentVC {

    override func viewDidLoad() {
        super.viewDidLoad()

        println(type)
        // Console prints out 1
    }
}

5
Xin cảm ơn, nó chỉ hoạt động, ví dụ:class func instantiate() -> SubClass { let instance = (UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("SuperClass") as? SuperClass)! object_setClass(instance, SubClass.self) return (instance as? SubClass)! }
CocoaBob

3
Tôi không chắc mình hiểu nó hoạt động như thế nào. Phụ huynh đang đặt lớp của nó là lớp của một đứa trẻ? Làm thế nào bạn có thể có nhiều con sau đó ?!
user1366265

2
bạn thưa ông, đã làm tôi day
Jere

2
Được rồi, hãy để tôi giải thích chi tiết hơn một chút: Chúng ta muốn đạt được điều gì? Chúng tôi muốn phân lớp ParentViewController của mình để chúng tôi có thể sử dụng Bảng phân cảnh của nó cho nhiều lớp hơn. Vì vậy, dòng ma thuật thực hiện tất cả được đánh dấu trong giải pháp của tôi và phải được sử dụng trong AwakeFromNib trong ParentVC. Điều xảy ra sau đó là nó sử dụng tất cả các phương thức từ ChildVC1 mới được thiết lập trở thành một lớp con. Nếu bạn muốn sử dụng nó cho nhiều ChildVC hơn? Đơn giản chỉ cần thực hiện logic của bạn trong wakeFromNib .. if (type = a) {object_setClass (self, ChildVC1.self)} else {object_setClass (self.ChildVC2.self)} Chúc may mắn.
Jiří Zahálka

10
Hãy rất cẩn thận khi sử dụng cái này! Thông thường điều này hoàn toàn không nên được sử dụng ... Điều này chỉ đơn giản là thay đổi con trỏ isa của con trỏ đã cho và không phân bổ lại bộ nhớ để chứa các thuộc tính khác nhau. Một chỉ báo cho điều này là con trỏ đến selfkhông thay đổi. Vì vậy, việc kiểm tra đối tượng (ví dụ: đọc giá trị _ivar / thuộc tính) sau khi object_setClasscó thể gây ra lỗi.
Patrik

15

Như câu trả lời được chấp nhận đã nêu, có vẻ như không thể làm với bảng phân cảnh.

Giải pháp của tôi là sử dụng Nib's - giống như các nhà phát triển đã sử dụng chúng trước khi có bảng phân cảnh. Nếu bạn muốn có một bộ điều khiển chế độ xem có thể tái sử dụng, có thể phân loại phụ (hoặc thậm chí là một chế độ xem), khuyến nghị của tôi là sử dụng Nibs.

SubclassMyViewController *myViewController = [[SubclassMyViewController alloc] initWithNibName:@"MyViewController" bundle:nil]; 

Khi bạn kết nối tất cả các cửa hàng của mình với "Chủ sở hữu tệp" trong MyViewController.xibbạn KHÔNG chỉ định lớp Nib sẽ được tải, bạn chỉ đang chỉ định các cặp khóa-giá trị: " chế độ xem này phải được kết nối với tên biến phiên bản này ." Khi gọi [SubclassMyViewController alloc] initWithNibName:quá trình khởi tạo chỉ định bộ điều khiển chế độ xem nào sẽ được sử dụng để " điều khiển " chế độ xem bạn đã tạo trong nib.


Đáng ngạc nhiên là điều này có thể thực hiện được với các bảng phân cảnh, nhờ vào thư viện thời gian chạy của ObjC. Kiểm tra câu trả lời của tôi tại đây: stackoverflow.com/a/57622836/7183675
Adam Tucholski

9

Có thể có bảng phân cảnh khởi tạo các lớp con khác nhau của bộ điều khiển chế độ xem tùy chỉnh, mặc dù nó liên quan đến một kỹ thuật hơi không chính thống: ghi đè allocphương thức cho bộ điều khiển chế độ xem. Khi bộ điều khiển chế độ xem tùy chỉnh được tạo, phương thức cấp phát ghi đè trên thực tế trả về kết quả của việc chạy alloctrên lớp con.

Tôi nên mở đầu câu trả lời với điều kiện rằng, mặc dù tôi đã thử nghiệm nó trong nhiều tình huống khác nhau và không nhận được lỗi nào, tôi không thể đảm bảo rằng nó sẽ đối phó với các thiết lập phức tạp hơn (nhưng tôi không hiểu lý do gì nó không hoạt động) . Ngoài ra, tôi chưa gửi bất kỳ ứng dụng nào bằng cách sử dụng phương pháp này, vì vậy có khả năng bên ngoài là nó có thể bị từ chối bởi quy trình xem xét của Apple (mặc dù một lần nữa tôi không thấy lý do tại sao lại như vậy).

Đối với mục đích trình diễn, tôi có một lớp con của UIViewControllerđược gọi TestViewController, lớp này có IBOutlet UILabel và IBAction. Trong bảng phân cảnh của mình, tôi đã thêm một bộ điều khiển chế độ xem và sửa đổi lớp của nó TestViewController, đồng thời kết nối IBOutlet với UILabel và IBAction với UIButton. Tôi trình bày TestViewController theo cách của một segue phương thức được kích hoạt bởi UIButton trên viewController trước đó.

Hình ảnh bảng phân cảnh

Để kiểm soát lớp nào được khởi tạo, tôi đã thêm một biến tĩnh và các phương thức lớp liên quan để lấy / đặt lớp con sẽ được sử dụng (tôi đoán người ta có thể áp dụng các cách khác để xác định lớp con nào sẽ được khởi tạo):

TestViewController.m:

#import "TestViewController.h"

@interface TestViewController ()
@end

@implementation TestViewController

static NSString *_classForStoryboard;

+(NSString *)classForStoryboard {
    return [_classForStoryboard copy];
}

+(void)setClassForStoryBoard:(NSString *)classString {
    if ([NSClassFromString(classString) isSubclassOfClass:[self class]]) {
        _classForStoryboard = [classString copy];
    } else {
        NSLog(@"Warning: %@ is not a subclass of %@, reverting to base class", classString, NSStringFromClass([self class]));
        _classForStoryboard = nil;
    }
}

+(instancetype)alloc {
    if (_classForStoryboard == nil) {
        return [super alloc];
    } else {
        if (NSClassFromString(_classForStoryboard) != [self class]) {
            TestViewController *subclassedVC = [NSClassFromString(_classForStoryboard) alloc];
            return subclassedVC;
        } else {
            return [super alloc];
        }
    }
}

Đối với bài kiểm tra của tôi, tôi có hai lớp con là TestViewController: RedTestViewControllerGreenTestViewController. Mỗi lớp con có các thuộc tính bổ sung và mỗi lớp ghi đè viewDidLoadđể thay đổi màu nền của dạng xem và cập nhật văn bản của UILabel IBOutlet:

RedTestViewController.m:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    self.view.backgroundColor = [UIColor redColor];
    self.testLabel.text = @"Set by RedTestVC";
}

GreenTestViewController.m:

- (void)viewDidLoad {
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor greenColor];
    self.testLabel.text = @"Set by GreenTestVC";
}

Trong một số trường hợp, tôi có thể muốn khởi tạo TestViewControllerchính nó, vào những dịp khác RedTestViewControllerhoặc GreenTestViewController. Trong bộ điều khiển chế độ xem trước, tôi thực hiện việc này một cách ngẫu nhiên như sau:

NSInteger vcIndex = arc4random_uniform(4);
if (vcIndex == 0) {
    NSLog(@"Chose TestVC");
    [TestViewController setClassForStoryBoard:@"TestViewController"];
} else if (vcIndex == 1) {
    NSLog(@"Chose RedVC");
    [TestViewController setClassForStoryBoard:@"RedTestViewController"];
} else if (vcIndex == 2) {
    NSLog(@"Chose BlueVC");
    [TestViewController setClassForStoryBoard:@"BlueTestViewController"];
} else {
    NSLog(@"Chose GreenVC");
    [TestViewController setClassForStoryBoard:@"GreenTestViewController"];
}

Lưu ý rằng setClassForStoryBoardphương thức kiểm tra để đảm bảo rằng tên lớp được yêu cầu thực sự là một lớp con của TestViewController, để tránh bất kỳ sự trộn lẫn nào. Tham khảo ở trên BlueTestViewControllerlà có để kiểm tra chức năng này.


Chúng tôi đã làm điều gì đó tương tự trong dự án, nhưng ghi đè phương thức cấp phát của UIViewController để lấy một lớp con từ một lớp bên ngoài thu thập thông tin đầy đủ về tất cả các ghi đè. Hoạt động hoàn hảo.
Tim

Bằng cách này, phương pháp này có thể ngừng hoạt động như fas ar khi Apple ngừng gọi phân bổ trên bộ điều khiển chế độ xem. Ví dụ, lớp NSManagedObject không bao giờ nhận được phương thức phân bổ. Tôi nghĩ rằng Apple có thể sao chép mã sang một phương pháp khác: có thể + certManagedObject
Tim

7

hãy thử điều này, sau khi InstantiateViewControllerWithIdentifier.

- (void)setClass:(Class)c {
    object_setClass(self, c);
}

giống :

SubViewController *vc = [sb instantiateViewControllerWithIdentifier:@"MainViewController"];
[vc setClass:[SubViewController class]];

Vui lòng thêm một số giải thích hữu ích về những gì mã của bạn làm.
codeforester

7
Điều gì xảy ra với điều này, nếu bạn sử dụng các biến cá thể từ lớp con? Tôi đoán sự cố, bởi vì không có đủ bộ nhớ được phân bổ để phù hợp với điều đó. Trong các thử nghiệm của tôi, tôi đã nhận được EXC_BAD_ACCESS, vì vậy không khuyến nghị điều này.
Legoless

1
Điều này sẽ không hoạt động nếu bạn thêm các biến mới trong lớp con. Và đứa trẻ initcũng sẽ không được gọi. Những ràng buộc như vậy làm cho tất cả các cách tiếp cận không thể sử dụng được.
Al Zonke

6

Đặc biệt dựa trên câu trả lời của nickgzzjrJiří Zahálka cộng với bình luận dưới câu trả lời thứ hai từ CocoaBob, tôi đã chuẩn bị phương pháp chung ngắn gọn để thực hiện chính xác những gì OP cần. Bạn chỉ cần kiểm tra tên bảng phân cảnh và ID bảng phân cảnh của View Controllers

class func instantiate<T: BasicViewController>(as _: T.Type) -> T? {
        let storyboard = UIStoryboard(name: "StoryboardName", bundle: nil)
        guard let instance = storyboard.instantiateViewController(withIdentifier: "Identifier") as? BasicViewController else {
            return nil
        }
        object_setClass(instance, T.self)
        return instance as? T
    }

Các tùy chọn được thêm vào để tránh buộc mở (cảnh báo nhanh), nhưng phương thức trả về các đối tượng chính xác.


5

Mặc dù nó không hoàn toàn là một lớp con, nhưng bạn có thể:

  1. option-hút bộ điều khiển chế độ xem lớp cơ sở trong Đề cương tài liệu để tạo bản sao
  2. Di chuyển bản sao bộ điều khiển chế độ xem mới đến một nơi riêng biệt trên bảng phân cảnh
  3. Thay đổi lớp thành bộ điều khiển chế độ xem lớp con trong Trình kiểm tra danh tính

Đây là một ví dụ từ một hướng dẫn Bloc mà tôi đã viết, phân lớp ViewControllervới WhiskeyViewController:

hoạt ảnh của ba bước trên

Điều này cho phép bạn tạo các lớp con của các lớp con của bộ điều khiển chế độ xem trong bảng phân cảnh. Sau đó, bạn có thể sử dụng instantiateViewControllerWithIdentifier:để tạo các lớp con cụ thể.

Cách tiếp cận này hơi thiếu linh hoạt: các sửa đổi sau này trong bảng phân cảnh đối với bộ điều khiển lớp cơ sở không truyền đến lớp con. Nếu bạn có nhiều lớp con, bạn có thể tốt hơn với một trong những giải pháp khác, nhưng điều này sẽ thực hiện một cách khó khăn.


11
Đây không phải là đối tác của lớp con, đây chỉ là bản sao một ViewController.
Ace Green,

1
Điều đó không đúng. Nó trở thành một lớp con khi bạn thay đổi Lớp thành lớp con (bước 3). Sau đó, bạn có thể thực hiện bất kỳ thay đổi nào bạn muốn và kết nối với các cửa hàng / hành động trong lớp con của bạn.
Aaron Brager

6
Tôi không nghĩ rằng bạn có khái niệm về phân lớp.
Ace Green

5
Nếu "các sửa đổi sau này trong bảng phân cảnh đối với bộ điều khiển lớp cơ sở không truyền đến lớp con", nó không được gọi là "lớp con". Đó là sao chép và dán.
superarts.org

Lớp cơ bản, được chọn trong Trình kiểm tra danh tính, vẫn là một lớp con. Đối tượng được khởi tạo và kiểm soát logic nghiệp vụ vẫn là một lớp con. Chỉ dữ liệu dạng xem được mã hóa, lưu trữ dưới dạng XML trong tệp bảng phân cảnh và được khởi tạo qua initWithCoder:, không có mối quan hệ kế thừa. Loại mối quan hệ này không được hỗ trợ bởi các tệp bảng phân cảnh.
Aaron Brager, 13/07/17

4

Phương thức objc_setclass không tạo một phiên bản của childvc. Nhưng trong khi bật ra khỏi childvc, deinit của childvc đang được gọi. Vì không có bộ nhớ nào được phân bổ riêng biệt cho childvc, ứng dụng bị treo. Basecontroller có một thể hiện, trong khi vc con không có.


2

Nếu không quá phụ thuộc vào bảng phân cảnh, bạn có thể tạo một tệp .xib riêng cho bộ điều khiển.

Đặt Chủ sở hữu và các cửa hàng của Tệp thích hợp thành MainViewControllervà ghi đè init(nibName:bundle:)trong VC chính để con của nó có thể truy cập vào cùng một Nib và các cửa hàng của nó.

Mã của bạn sẽ giống như sau:

class MainViewController: UIViewController {
    @IBOutlet weak var button: UIButton!

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: "MainViewController", bundle: nil)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        button.tintColor = .red
    }
}

Và VC Con của bạn sẽ có thể sử dụng lại ngòi của cha mẹ nó:

class ChildViewController: MainViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        button.tintColor = .blue
    }
}

2

Lấy câu trả lời từ đây và ở đó, tôi đã đưa ra giải pháp gọn gàng này.

Tạo bộ điều khiển chế độ xem chính với chức năng này.

class ParentViewController: UIViewController {


    func convert<T: ParentViewController>(to _: T.Type) {

        object_setClass(self, T.self)

    }

}

Điều này cho phép trình biên dịch đảm bảo rằng bộ điều khiển chế độ xem con kế thừa từ bộ điều khiển chế độ xem mẹ.

Sau đó, bất cứ khi nào bạn muốn phân biệt bộ điều khiển này bằng cách sử dụng một lớp con, bạn có thể thực hiện:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    super.prepare(for: segue, sender: sender)

    if let parentViewController = segue.destination as? ParentViewController {
        ParentViewController.convert(to: ChildViewController.self)
    }

}

Phần thú vị là bạn có thể thêm một tham chiếu bảng phân cảnh vào chính nó, và sau đó tiếp tục gọi bộ điều khiển chế độ xem con "tiếp theo".


1

Có lẽ cách linh hoạt nhất là sử dụng các khung nhìn có thể tái sử dụng.

(Tạo Chế độ xem trong tệp XIB riêng biệt hoặc Container viewvà thêm nó vào từng cảnh bộ điều khiển chế độ xem lớp con trong bảng phân cảnh)


1
Hãy bình luận khi bạn phản đối. Tôi biết rằng tôi không trả lời trực tiếp câu hỏi đó nhưng tôi đề xuất một giải pháp cho vấn đề gốc rễ.
DanSkeel

1

Có một giải pháp đơn giản, hiển nhiên, hàng ngày.

Chỉ cần đặt bảng phân cảnh / bộ điều khiển hiện có bên trong bảng phân cảnh / bộ điều khiển mới. IE dưới dạng khung nhìn vùng chứa.

Đây là khái niệm tương tự chính xác với "phân lớp", cho, bộ điều khiển xem.

Mọi thứ hoạt động chính xác như trong một lớp con.

Cũng giống như bạn thường đặt một chế độ xem phụ bên trong một chế độ xem khác , tự nhiên bạn thường đặt một bộ điều khiển chế độ xem bên trong một bộ điều khiển chế độ xem khác .

Bạn có thể làm điều đó bằng cách nào khác?

Đó là một phần cơ bản của iOS, đơn giản như khái niệm "subview".

Thật dễ dàng ...

/*

Search screen is just a modification of our List screen.

*/

import UIKit

class Search: UIViewController {
    
    var list: List!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        list = (_sb("List") as! List
        addChild(list)
        view.addSubview(list.view)
        list.view.bindEdgesToSuperview()
        list.didMove(toParent: self)
    }
}

Bây giờ bạn rõ ràng phải listlàm bất cứ điều gì bạn muốn với

list.mode = .blah
list.tableview.reloadData()
list.heading = 'Search!'
list.searchBar.isHidden = false

Vân vân.

Lượt xem vùng chứa là phân lớp "giống như" giống như cách mà "lượt xem con" là phân lớp "giống như".

Tất nhiên, rõ ràng là bạn không thể "sublcass a layout" - điều đó thậm chí có nghĩa là gì?

("Phân lớp" liên quan đến phần mềm OO và không có kết nối với "bố cục".)

Rõ ràng khi bạn muốn sử dụng lại một chế độ xem, bạn chỉ cần xem lại nó bên trong một chế độ xem khác.

Khi bạn muốn sử dụng lại bố cục bộ điều khiển, bạn chỉ cần xem vùng chứa bên trong bộ điều khiển khác.

Đây giống như cơ chế cơ bản nhất của iOS !!


Lưu ý - trong nhiều năm nay, việc tải động một bộ điều khiển chế độ xem khác dưới dạng chế độ xem vùng chứa là điều rất bình thường. Giải thích trong phần cuối cùng: https://stackoverflow.com/a/23403979/294884

Lưu ý - "_sb" chỉ là một macro hiển nhiên mà chúng tôi sử dụng để lưu việc nhập,

func _sb(_ s: String)->UIViewController {
    // by convention, for a screen "SomeScreen.storyboard" the
    // storyboardID must be SomeScreenID
    return UIStoryboard(name: s, bundle: nil)
       .instantiateViewController(withIdentifier: s + "ID")
}

1

Cảm ơn câu trả lời đầy cảm hứng của @ Jiří Zahálka, tôi đã trả lời giải pháp của mình cách đây 4 năm ở đây , nhưng @Sayka đã đề nghị tôi đăng nó như một câu trả lời, vì vậy nó là ở đây.

Trong các dự án của tôi, thông thường, nếu tôi đang sử dụng Storyboard cho một lớp con UIViewController, tôi luôn chuẩn bị một phương thức tĩnh được gọi instantiate()trong lớp con đó, để tạo một thể hiện từ Storyboard một cách dễ dàng. Vì vậy, để giải quyết câu hỏi của OP, nếu chúng ta muốn chia sẻ cùng một Storyboard cho các lớp con khác nhau, chúng ta có thể chỉ cần setClass()đến cá thể đó trước khi trả về.

class func instantiate() -> SubClass {
    let instance = (UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("SuperClass") as? SuperClass)!
    object_setClass(instance, SubClass.self)
    return (instance as? SubClass)!
}

0

Nhận xét của Cocoabob từ câu trả lời của Jiří Zahálka đã giúp tôi có được giải pháp này và nó hoạt động tốt.

func openChildA() {
    let storyboard = UIStoryboard(name: "Main", bundle: nil);
    let parentController = storyboard
        .instantiateViewController(withIdentifier: "ParentStoryboardID") 
        as! ParentClass;
    object_setClass(parentController, ChildA.self)
    self.present(parentController, animated: true, completion: nil);
}
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.