Truyền dữ liệu giữa các bộ điều khiển xem


1372

Tôi mới sử dụng iOS và Objective-C và toàn bộ mô hình MVC và tôi bị mắc kẹt với những điều sau:

Tôi có một chế độ xem hoạt động như một biểu mẫu nhập dữ liệu và tôi muốn cung cấp cho người dùng tùy chọn để chọn nhiều sản phẩm. Các sản phẩm được liệt kê trên một chế độ xem khác với a UITableViewControllervà tôi đã kích hoạt nhiều lựa chọn.

Câu hỏi của tôi là, làm cách nào để chuyển dữ liệu từ chế độ xem này sang chế độ xem khác? Tôi sẽ giữ các lựa chọn trên UITableViewmột mảng, nhưng làm cách nào để chuyển nó trở lại chế độ xem biểu mẫu nhập dữ liệu trước đó để có thể lưu cùng với dữ liệu khác vào Dữ liệu lõi khi gửi biểu mẫu?

Tôi đã lướt xung quanh và thấy một số người tuyên bố một mảng trong đại biểu ứng dụng. Tôi đã đọc một cái gì đó về Singletons nhưng không hiểu những thứ này là gì và tôi đọc một cái gì đó về việc tạo một mô hình dữ liệu.

Điều gì sẽ là cách chính xác để thực hiện điều này và làm thế nào tôi sẽ đi về nó?

Câu trả lời:


1684

Câu hỏi này dường như rất phổ biến ở đây trên stackoverflow vì vậy tôi nghĩ rằng tôi sẽ thử và đưa ra câu trả lời tốt hơn để giúp đỡ những người bắt đầu trong thế giới iOS như tôi.

Tôi hy vọng câu trả lời này đủ rõ ràng để mọi người hiểu và tôi không bỏ sót điều gì.

Truyền dữ liệu chuyển tiếp

Truyền dữ liệu về phía trước cho bộ điều khiển xem từ bộ điều khiển xem khác. Bạn sẽ sử dụng phương thức này nếu bạn muốn chuyển một đối tượng / giá trị từ một bộ điều khiển khung nhìn sang một bộ điều khiển khung nhìn khác mà bạn có thể đang đẩy vào ngăn xếp điều hướng.

Trong ví dụ này, chúng ta sẽ có ViewControllerAViewControllerB

Để vượt qua một BOOLgiá trị từ ViewControllerAđể ViewControllerBchúng ta sẽ làm như sau.

  1. trong việc ViewControllerB.htạo một tài sản choBOOL

    @property (nonatomic, assign) BOOL isSomethingEnabled;
  2. trong ViewControllerAbạn cần nói với nó về việc ViewControllerBsử dụng một

    #import "ViewControllerB.h"

    Sau đó, nơi bạn muốn tải xem, ví dụ. didSelectRowAtIndexhoặc một số IBActionbạn cần đặt thuộc tính ViewControllerBtrước khi đẩy nó lên ngăn xếp điều hướng.

    ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
    viewControllerB.isSomethingEnabled = YES;
    [self pushViewController:viewControllerB animated:YES];
    

    Điều này sẽ thiết lập isSomethingEnabledtrong ViewControllerBđể BOOLgiá trị YES.

Truyền chuyển tiếp dữ liệu bằng cách sử dụng phân đoạn

Nếu bạn đang sử dụng Storyboards, rất có thể bạn đang sử dụng segues và sẽ cần quy trình này để truyền dữ liệu về phía trước. Điều này tương tự như ở trên nhưng thay vì truyền dữ liệu trước khi bạn đẩy bộ điều khiển xem, bạn sử dụng một phương thức được gọi là

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

Vì vậy, để vượt qua một BOOLtừ ViewControllerAđể ViewControllerBchúng ta sẽ làm như sau:

  1. trong việc ViewControllerB.htạo một tài sản choBOOL

    @property (nonatomic, assign) BOOL isSomethingEnabled;
  2. trong ViewControllerAbạn cần nói với nó về việc ViewControllerBsử dụng một

    #import "ViewControllerB.h"
  3. Tạo một segue từ ViewControllerAđến ViewControllerBtrên bảng phân cảnh và cung cấp cho nó một định danh, trong ví dụ này chúng ta sẽ gọi nó"showDetailSegue"

  4. Tiếp theo, chúng ta cần thêm phương thức vào ViewControllerAđó được gọi khi bất kỳ segue nào được thực hiện, vì điều này chúng ta cần phát hiện ra segue nào được gọi và sau đó thực hiện một cái gì đó. Trong ví dụ của chúng tôi, chúng tôi sẽ kiểm tra "showDetailSegue"và nếu điều đó được thực hiện, chúng tôi sẽ chuyển BOOLgiá trị của mình choViewControllerB

    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
        if([segue.identifier isEqualToString:@"showDetailSegue"]){
            ViewControllerB *controller = (ViewControllerB *)segue.destinationViewController;
            controller.isSomethingEnabled = YES;
        }
    }

    Nếu bạn có chế độ xem của mình được nhúng trong bộ điều khiển điều hướng, bạn cần thay đổi phương thức trên một chút thành sau

    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
        if([segue.identifier isEqualToString:@"showDetailSegue"]){
            UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
            ViewControllerB *controller = (ViewControllerB *)navController.topViewController;
            controller.isSomethingEnabled = YES;
        }
    }

    Điều này sẽ thiết lập isSomethingEnabledtrong ViewControllerBđể BOOLgiá trị YES.

Truyền lại dữ liệu

Để truyền lại dữ liệu ViewControllerBcho ViewControllerAbạn, bạn cần sử dụng Giao thức và Đại biểu hoặc Khối , cái sau có thể được sử dụng như một cơ chế kết hợp lỏng lẻo cho các cuộc gọi lại.

Để làm điều này, chúng tôi sẽ làm cho ViewControllerAmột đại biểu ViewControllerB. Điều này cho phép ViewControllerBgửi lại tin nhắn để ViewControllerAcho phép chúng tôi gửi lại dữ liệu.

Để ViewControllerAtrở thành đại biểu của ViewControllerBnó phải tuân thủ ViewControllerBgiao thức mà chúng ta phải chỉ định. Điều này cho biết ViewControllerAnó phải thực hiện phương pháp nào.

  1. Trong ViewControllerB.h, bên dưới #import, nhưng ở trên @interfacebạn chỉ định giao thức.

    @class ViewControllerB;
    
    @protocol ViewControllerBDelegate <NSObject>
    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
    @end
  2. tiếp theo vẫn còn trong ViewControllerB.hbạn cần thiết lập một thuộc delegatetính và tổng hợp trongViewControllerB.m

    @property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
  3. Trong ViewControllerBchúng tôi gọi một thông báo delegatekhi chúng tôi bật bộ điều khiển xem.

    NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
    [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
  4. Đó là nó cho ViewControllerB. Bây giờ ViewControllerA.h, nói ViewControllerAđể nhập ViewControllerBvà tuân thủ giao thức của nó.

    #import "ViewControllerB.h"
    
    @interface ViewControllerA : UIViewController <ViewControllerBDelegate>
  5. Trong ViewControllerA.mviệc thực hiện các phương pháp sau từ giao thức của chúng tôi

    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
    {
        NSLog(@"This was returned from ViewControllerB %@",item);
    }
  6. Trước khi đẩy viewControllerBvào ngăn xếp điều hướng, chúng ta cần phải biết ViewControllerBđó ViewControllerAlà đại biểu của nó, nếu không chúng ta sẽ gặp lỗi.

    ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
    viewControllerB.delegate = self
    [[self navigationController] pushViewController:viewControllerB animated:YES];

Người giới thiệu

  1. Sử dụng Phân quyền để Giao tiếp với Bộ điều khiển Chế độ xem Khác trong Hướng dẫn Lập trình Trình điều khiển Xem
  2. Mẫu đại biểu

Trung tâm NSNotification Đó là một cách khác để truyền dữ liệu.

// add observer in controller(s) where you want to receive data
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDeepLinking:) name:@"handleDeepLinking" object:nil];

-(void) handleDeepLinking:(NSNotification *) notification {
    id someObject = notification.object // some custom object that was passed with notification fire.
}

// post notification
id someObject;
[NSNotificationCenter.defaultCenter postNotificationName:@"handleDeepLinking" object:someObject];

Truyền dữ liệu trở lại từ lớp này sang lớp khác (Một lớp có thể là bất kỳ bộ điều khiển, trình quản lý mạng / phiên, lớp con UIView hoặc bất kỳ lớp nào khác)

Khối là các chức năng ẩn danh.

Ví dụ này chuyển dữ liệu từ Bộ điều khiển B sang Bộ điều khiển A

xác định một khối

@property void(^selectedVoucherBlock)(NSString *); // in ContollerA.h

thêm trình xử lý khối (trình nghe) trong đó bạn cần một giá trị (ví dụ: bạn cần phản hồi API của mình trong ControllerA hoặc bạn cần dữ liệu ContorllerB trên A)

// in ContollerA.m

- (void)viewDidLoad {
    [super viewDidLoad];
    __unsafe_unretained typeof(self) weakSelf = self;
    self.selectedVoucherBlock = ^(NSString *voucher) {
        weakSelf->someLabel.text = voucher;
    };
}

Chuyển đến Trình điều khiển B

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
ControllerB *vc = [storyboard instantiateViewControllerWithIdentifier:@"ControllerB"];
vc.sourceVC = self;
    [self.navigationController pushViewController:vc animated:NO];

khối lửa

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: 
(NSIndexPath *)indexPath {
    NSString *voucher = vouchersArray[indexPath.row];
    if (sourceVC.selectVoucherBlock) {
        sourceVC.selectVoucherBlock(voucher);
    }
    [self.navigationController popToViewController:sourceVC animated:YES];
}

Một ví dụ hoạt động khác cho các khối


24
Chúng ta cũng phải đặt một @class ViewControllerB;định nghĩa trên @protatio? Nếu không có nó, tôi gặp lỗi "Loại dự kiến" trên ViewContoderB trong dòng: - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item; trong phần @protocolkhai báo
alan-p

4
Điều này làm việc tuyệt vời. Như alan-p nói, đừng quên viết @ class ViewContoderB; trên giao thức nếu không bạn sẽ nhận được lỗi "Dự kiến ​​một loại".
Andrew Davis

6
bạn không cần đại biểu để quay trở lại, chỉ cần sử dụng thư giãn.
malhal

4
Khi tôi đặt "viewControllB.delegate = self;" trong ViewControllB tôi đang gặp lỗi. Gán cho 'id <ViewControllBDelegate>' từ loại không tương thích 'ViewControllB * const __strong', tôi không chắc mình đang làm gì sai. Có ai giúp được không? Thêm vào đó tôi đã phải thay đổi: initWithNib -> initWithNibName.
uplearnedu.com

4
nếu bạn đang sử dụng, NavigationControllerbạn phải sử dụng [self.navigationController pushViewController:viewController animated:YES];thay thế[self pushViewController:viewControllerB animated:YES];
Nazir

192

Nhanh

Có rất nhiều lời giải thích ở đây và xung quanh StackOverflow, nhưng nếu bạn là người mới bắt đầu chỉ cố gắng để có một cái gì đó cơ bản để làm việc, hãy thử xem hướng dẫn trên YouTube này (Điều đó đã giúp tôi cuối cùng hiểu cách làm nó).

Truyền dữ liệu tới Bộ điều khiển xem tiếp theo

Sau đây là một ví dụ dựa trên video. Ý tưởng là chuyển một chuỗi từ trường văn bản trong Trình điều khiển Chế độ xem Đầu tiên sang nhãn trong Trình điều khiển Chế độ xem Thứ hai.

nhập mô tả hình ảnh ở đây

Tạo bố cục bảng phân cảnh trong Trình tạo giao diện. Để tạo sự khác biệt, bạn chỉ cần Controlnhấp vào nút và kéo qua Trình điều khiển Chế độ xem Thứ hai.

Bộ điều khiển xem đầu tiên

Mã cho Trình điều khiển Chế độ xem Đầu tiên là

import UIKit

class FirstViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!

    // This function is called before the segue
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        // get a reference to the second view controller
        let secondViewController = segue.destination as! SecondViewController

        // set a variable in the second view controller with the String to pass
        secondViewController.receivedString = textField.text!
    }

}

Bộ điều khiển xem thứ hai

Và mã cho Trình điều khiển Chế độ xem Thứ hai là

import UIKit

class SecondViewController: UIViewController {

    @IBOutlet weak var label: UILabel!

    // This variable will hold the data being passed from the First View Controller
    var receivedString = ""

    override func viewDidLoad() {
        super.viewDidLoad()

        // Used the text from the First View Controller to set the label
        label.text = receivedString
    }

}

Đừng quên

  • Móc ra các cửa hàng cho UITextFieldUILabel.
  • Đặt Bộ điều khiển Chế độ xem thứ nhất và thứ hai thành các tệp Swift thích hợp trong IB.

Truyền dữ liệu trở lại Trình điều khiển xem trước đó

Để chuyển dữ liệu trở lại từ bộ điều khiển khung nhìn thứ hai sang bộ điều khiển khung nhìn thứ nhất, bạn sử dụng một giao thức và một ủy nhiệm . Video này là một bước đi rất rõ ràng mặc dù quá trình đó:

Sau đây là một ví dụ dựa trên video (với một vài sửa đổi).

nhập mô tả hình ảnh ở đây

Tạo bố cục bảng phân cảnh trong Trình tạo giao diện. Một lần nữa, để tạo ra sự khác biệt, bạn chỉ cần Controlkéo từ nút vào Trình điều khiển Chế độ xem Thứ hai. Đặt định danh segue thành showSecondViewController. Ngoài ra, đừng quên kết nối các cửa hàng và hành động bằng cách sử dụng tên trong mã sau đây.

Bộ điều khiển xem đầu tiên

Mã cho Trình điều khiển Chế độ xem Đầu tiên là

import UIKit

class FirstViewController: UIViewController, DataEnteredDelegate {

    @IBOutlet weak var label: UILabel!

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showSecondViewController" {
            let secondViewController = segue.destination as! SecondViewController
            secondViewController.delegate = self
        }
    }

    func userDidEnterInformation(info: String) {
        label.text = info
    }
}

Lưu ý việc sử dụng DataEnteredDelegategiao thức tùy chỉnh của chúng tôi .

Bộ điều khiển và giao thức xem thứ hai

Mã cho bộ điều khiển xem thứ hai là

import UIKit

// protocol used for sending data back
protocol DataEnteredDelegate: AnyObject {
    func userDidEnterInformation(info: String)
}

class SecondViewController: UIViewController {

    // making this a weak variable so that it won't create a strong reference cycle
    weak var delegate: DataEnteredDelegate? = nil

    @IBOutlet weak var textField: UITextField!

    @IBAction func sendTextBackButton(sender: AnyObject) {

        // call this method on whichever class implements our delegate protocol
        delegate?.userDidEnterInformation(info: textField.text!)

        // go back to the previous view controller
        _ = self.navigationController?.popViewController(animated: true)
    }
}

Lưu ý rằng protocolbên ngoài lớp Trình điều khiển xem.

Đó là nó. Chạy ứng dụng bây giờ bạn sẽ có thể gửi lại dữ liệu từ bộ điều khiển chế độ xem thứ hai đến bộ điều khiển thứ nhất.


Đưa ra một số cập nhật mới nhất của Swift, đây có còn là mô hình phổ biến để thực hiện không?
piofusco

4
Hầu hết tất cả các bản cập nhật Swift mà tôi thấy là những thay đổi cú pháp tương đối nhỏ, không thay đổi về cách dữ liệu được truyền giữa các bộ điều khiển xem. Nếu tôi biết được bất kỳ thay đổi lớn nào như vậy, tôi sẽ cập nhật câu trả lời của mình.
Suragch

2
offtopic - iOS có một cách xấu xí như vậy để truyền tham số cho bộ điều khiển chế độ xem mới, không thể tin được - bạn phải đặt tham số không ở một nơi khi bạn thực hiện cuộc gọi, nhưng ở một số khác. Android có cách tiếp cận tốt hơn trong vấn đề này - khi bạn bắt đầu một Hoạt động, bạn có thể truyền bất kỳ dữ liệu nào (tốt, gần như) thông qua Ý định bắt đầu. Dễ dàng. Không cần phải đúc hoặc một cái gì đó. Truyền lại giá trị trả lại cho người gọi cũng là một điều thiết yếu, không cần phải ủy thác. Tất nhiên cũng có thể sử dụng các cách tiếp cận xấu xí, không có vấn đề gì ở đó))
Mixaz

1
@Himanshu, trước tiên hãy tham khảo bộ điều khiển xem thứ hai. Sau đó cập nhật biến công khai mà nó chứa.
Suragch

8
@Mật ong. Tôi nghĩ từ "đại biểu" là khó hiểu. Hãy để tôi sử dụng từ "công nhân". "Công nhân" (bộ điều khiển khung nhìn thứ nhất) làm bất cứ điều gì "ông chủ" (bộ điều khiển khung nhìn thứ hai) bảo nó làm. "Sếp" không biết "công nhân" của mình sẽ là ai; nó có thể là bất cứ ai Vì vậy, trong trình điều khiển khung nhìn đầu tiên (lớp "worker"), nó nói, tôi sẽ là "worker" của bạn. Bạn cho tôi biết những gì để viết trong nhãn và tôi sẽ làm điều đó cho bạn. Do đó, secondViewController.delegate = selfcó nghĩa là "Tôi đồng ý làm nhân viên của ông chủ." Xem câu trả lời này cho một ví dụ khác và giải thích thêm.
Suragch

136

M trong MVC dành cho "Model" và trong mô hình MVC, vai trò của các lớp mô hình là quản lý dữ liệu của chương trình. Một mô hình ngược lại với một khung nhìn - một khung nhìn biết cách hiển thị dữ liệu, nhưng nó không biết gì về việc phải làm gì với dữ liệu, trong khi một mô hình biết mọi thứ về cách làm việc với dữ liệu, nhưng không biết cách hiển thị dữ liệu. Các mô hình có thể phức tạp, nhưng chúng không phải như vậy - mô hình cho ứng dụng của bạn có thể đơn giản như một chuỗi các chuỗi hoặc từ điển.

Vai trò của bộ điều khiển là làm trung gian giữa khung nhìn và mô hình. Do đó, họ cần một tham chiếu đến một hoặc nhiều đối tượng xem và một hoặc nhiều đối tượng mô hình. Giả sử mô hình của bạn là một loạt các từ điển, với mỗi từ điển đại diện cho một hàng trong bảng của bạn. Chế độ xem gốc cho ứng dụng của bạn hiển thị bảng đó và nó có thể chịu trách nhiệm tải mảng từ tệp. Khi người dùng quyết định thêm một hàng mới vào bảng, họ nhấn một số nút và bộ điều khiển của bạn sẽ tạo một từ điển mới (có thể thay đổi) và thêm nó vào mảng. Để điền vào hàng, bộ điều khiển tạo một bộ điều khiển xem chi tiết và cung cấp cho nó từ điển mới. Trình điều khiển xem chi tiết điền vào từ điển và trả về. Từ điển đã là một phần của mô hình, vì vậy không có gì khác cần phải xảy ra.


95

Có nhiều cách khác nhau để dữ liệu có thể được nhận đến một lớp khác trong iOS. Ví dụ -

  1. Khởi tạo trực tiếp sau khi phân bổ một lớp khác.
  2. Đoàn - để truyền dữ liệu trở lại
  3. Thông báo - để truyền phát dữ liệu tới nhiều lớp cùng một lúc
  4. Lưu vào NSUserDefaults- để truy cập sau
  5. Lớp học đơn
  6. Cơ sở dữ liệu và các cơ chế lưu trữ khác như plist, v.v.

Nhưng đối với kịch bản đơn giản là chuyển một giá trị cho một lớp khác có phân bổ được thực hiện trong lớp hiện tại, phương thức phổ biến và được ưa thích nhất sẽ là cài đặt trực tiếp các giá trị sau khi phân bổ. Điều này được thực hiện như sau:-

Chúng ta có thể hiểu nó bằng hai bộ điều khiển - Controller1 và Controller2

Giả sử trong lớp Controller1 bạn muốn tạo đối tượng Controller2 và đẩy nó với giá trị String được truyền. Điều này có thể được thực hiện như sau: -

- (void)pushToController2 {

    Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
    [obj passValue:@"String"];
    [self pushViewController:obj animated:YES];
}

Trong quá trình thực hiện lớp Controller2 sẽ có chức năng này như-

@interface Controller2  : NSObject

@property (nonatomic , strong) NSString* stringPassed;

@end

@implementation Controller2

@synthesize stringPassed = _stringPassed;

- (void) passValue:(NSString *)value {

    _stringPassed = value; //or self.stringPassed = value
}

@end

Bạn cũng có thể trực tiếp thiết lập các thuộc tính của lớp Controller2 theo cách tương tự như sau:

- (void)pushToController2 {

    Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
    [obj setStringPassed:@"String"];  
    [self pushViewController:obj animated:YES];
}

Để truyền nhiều giá trị, bạn có thể sử dụng nhiều tham số như: -

Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
[obj passValue:@“String1 andValues:objArray withDate:date]; 

Hoặc nếu bạn cần truyền nhiều hơn 3 tham số có liên quan đến một tính năng phổ biến, bạn có thể lưu trữ các giá trị cho một lớp Model và truyền modelObject đó cho lớp tiếp theo

ModelClass *modelObject = [[ModelClass alloc] init]; 
modelObject.property1 = _property1;
modelObject.property2 = _property2;
modelObject.property3 = _property3;

Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
[obj passmodel: modelObject];

Vì vậy, trong ngắn hạn nếu bạn muốn -

1) set the private variables of the second class initialise the values by calling a custom function and passing the values.
2) setProperties do it by directlyInitialising it using the setter method.
3) pass more that 3-4 values related to each other in some manner , then create a model class and set values to its object and pass the object using any of the above process.

Hi vọng điêu nay co ich


84

Sau khi nghiên cứu thêm, có vẻ như Giao thức và Đại biểu là cách chính xác / Apple thích làm việc này.

Tôi đã kết thúc bằng cách sử dụng ví dụ này

Chia sẻ dữ liệu giữa các bộ điều khiển xem và các đối tượng khác @ iPhone Dev SDK

Hoạt động tốt và cho phép tôi chuyển một chuỗi và một mảng tiến và lùi giữa các khung nhìn của tôi.

Cảm ơn tất cả sự giúp đỡ của bạn


3
không sử dụng giao thức và đại biểu, chỉ sử dụng thư giãn.
malhal

1
@malhal Nếu bạn không sử dụng bảng phân cảnh thì sao ??
Evan R

Tôi ghét các giao thức vô dụng và các đại biểu, quá. @malhal
DawnSong

@EvanR Bạn có thể tạo và thực hiện các phân đoạn trong mã. Tất cả đều giống nhau.
DawnSong

1
Về cơ bản, toàn bộ QA trên trang này là "từ ngày xưa trước khi xem container". Bạn sẽ không bao giờ trong một triệu năm bận tâm với các giao thức hoặc đại biểu bây giờ. Mọi điều nhỏ bạn làm trên bất kỳ màn hình nào đều là chế độ xem container, vì vậy, câu hỏi thực sự không còn tồn tại - bạn đã có tất cả các tham chiếu "lên xuống" từ tất cả các chế độ xem của container.
Fattie

66

Tôi tìm thấy phiên bản đơn giản và thanh lịch nhất với các khối đi qua. Hãy để bộ điều khiển xem tên chờ dữ liệu trả về là "A" và trả về bộ điều khiển xem là "B". Trong ví dụ này, chúng tôi muốn nhận 2 giá trị: đầu tiên là Type1 và thứ hai của Type2.

Giả sử chúng ta sử dụng Storyboard, bộ điều khiển đầu tiên đặt khối gọi lại, ví dụ như trong quá trình chuẩn bị segue:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.destinationViewController isKindOfClass:[BViewController class]])
    {
        BViewController *viewController = segue.destinationViewController;

        viewController.callback = ^(Type1 *value1, Type2 *value2) {
            // optionally, close B
            //[self.navigationController popViewControllerAnimated:YES];

            // let's do some action after with returned values
            action1(value1);
            action2(value2);
        };

    }
}

và trình điều khiển xem "B" sẽ khai báo thuộc tính gọi lại, BViewControll.h:

// it is important to use "copy"
@property (copy) void(^callback)(Type1 *value1, Type2 *value2);

Hơn trong tệp triển khai BViewControll.m sau khi chúng tôi có các giá trị mong muốn để trả về cuộc gọi lại của chúng tôi sẽ được gọi:

if (self.callback)
    self.callback(value1, value2);

Một điều cần nhớ là sử dụng khối thường cần quản lý các tham chiếu mạnh và __weak như được giải thích ở đây


Tại sao giá trị không phải là một tham số cho khối gọi lại chứ không phải là một thuộc tính riêng biệt?
Timuçin

56

Có một số thông tin tốt trong nhiều câu trả lời được đưa ra, nhưng không có câu trả lời nào đầy đủ cho câu hỏi.

Câu hỏi hỏi về việc chuyển thông tin giữa các bộ điều khiển xem. Ví dụ cụ thể được đưa ra hỏi về việc chuyển thông tin giữa các lượt xem, nhưng với sự mới mẻ tự nêu cho iOS, áp phích ban đầu có thể có nghĩa là giữa viewControllers, không phải giữa các lượt xem (không có sự tham gia của ViewControllers). Có vẻ như tất cả các câu trả lời tập trung vào hai bộ điều khiển xem, nhưng nếu ứng dụng phát triển cần liên quan đến nhiều hơn hai bộ điều khiển xem trong trao đổi thông tin thì sao?

Người đăng ban đầu cũng hỏi về Singletons và việc sử dụng AppDelegate . Những câu hỏi cần phải được trả lời.

Để giúp bất cứ ai khác nhìn vào câu hỏi này, ai muốn có câu trả lời đầy đủ, tôi sẽ cố gắng cung cấp nó.

Kịch bản ứng dụng

Thay vì có một cuộc thảo luận trừu tượng, mang tính giả thuyết, nó giúp có những ứng dụng cụ thể trong tâm trí. Để giúp xác định tình huống của trình điều khiển hai chế độ xem và tình huống của trình điều khiển hai chế độ xem, tôi sẽ định nghĩa hai kịch bản ứng dụng cụ thể.

Kịch bản một: tối đa hai bộ điều khiển xem bao giờ cần chia sẻ thông tin. Xem sơ đồ một.

sơ đồ của vấn đề ban đầu

Có hai bộ điều khiển xem trong ứng dụng. Có một ViewContoderA (Biểu mẫu nhập dữ liệu) và Trình điều khiển xem B (Danh sách sản phẩm). Các mục được chọn trong danh sách sản phẩm phải khớp với các mục được hiển thị trong hộp văn bản trong biểu mẫu nhập dữ liệu. Trong trường hợp này, ViewControllA và ViewControllB phải giao tiếp trực tiếp với nhau và không có bộ điều khiển xem khác.

Kịch bản hai : nhiều hơn hai bộ điều khiển xem cần chia sẻ cùng một thông tin. Xem sơ đồ hai.

sơ đồ ứng dụng hàng tồn kho

Có bốn bộ điều khiển xem trong ứng dụng. Nó là một ứng dụng dựa trên tab để quản lý hàng tồn kho trong nhà. Ba bộ điều khiển khung nhìn thể hiện các khung nhìn được lọc khác nhau của cùng một dữ liệu:

  • ViewControllA - Vật phẩm xa xỉ
  • ViewControllB - Các mặt hàng không được bảo hiểm
  • ViewControllC - Toàn bộ hàng tồn kho tại nhà
  • ViewControllD - Thêm mẫu vật phẩm mới

Bất cứ khi nào một mục riêng lẻ được tạo hoặc chỉnh sửa, nó cũng phải đồng bộ hóa với các bộ điều khiển xem khác. Ví dụ: nếu chúng ta thêm một chiếc thuyền trong ViewControllD, nhưng nó chưa được bảo hiểm, thì chiếc thuyền đó phải xuất hiện khi người dùng truy cập ViewContoderA (Vật phẩm xa xỉ) và cả ViewContoderC (Entire Home Inventory), nhưng không phải khi người dùng đi đến ViewControllB (Các mặt hàng không được bảo hiểm). Chúng tôi cần quan tâm đến việc không chỉ thêm các mục mới mà còn xóa các mục (có thể được cho phép từ bất kỳ bộ điều khiển bốn chế độ xem nào) hoặc chỉnh sửa các mục hiện có (có thể được cho phép từ "Thêm biểu mẫu mục mới", tương tự như vậy để chỉnh sửa).

Vì tất cả các bộ điều khiển chế độ xem cần chia sẻ cùng một dữ liệu, cả bốn bộ điều khiển chế độ xem cần duy trì đồng bộ hóa và do đó cần có một số loại giao tiếp với tất cả các bộ điều khiển chế độ xem khác, bất cứ khi nào bộ điều khiển xem đơn lẻ thay đổi dữ liệu bên dưới. Một điều khá rõ ràng là chúng ta không muốn mỗi bộ điều khiển khung nhìn giao tiếp trực tiếp với bộ điều khiển khung nhìn khác trong kịch bản này. Trong trường hợp không rõ ràng, hãy xem xét nếu chúng tôi có 20 bộ điều khiển xem khác nhau (thay vì chỉ 4). Làm thế nào khó khăn và dễ bị lỗi để thông báo cho mỗi trong số 19 bộ điều khiển xem khác bất cứ khi nào một bộ điều khiển xem thực hiện thay đổi?

Các giải pháp: Đại biểu và Mẫu người quan sát và Singletons

Trong kịch bản một, chúng tôi có một số giải pháp khả thi, như các câu trả lời khác đã đưa ra

  • biệt
  • đại biểu
  • cài đặt thuộc tính trên bộ điều khiển xem trực tiếp
  • NSUserDefaults (thực sự là một lựa chọn kém)

Trong kịch bản hai, chúng tôi có các giải pháp khả thi khác:

  • Mẫu quan sát
  • Người độc thân

Một singleton là một thể hiện của một lớp, cá thể đó là trường hợp duy nhất tồn tại trong suốt vòng đời của nó. Một singleton có tên của nó từ thực tế rằng đó là trường hợp duy nhất. Thông thường các nhà phát triển sử dụng singletons có các phương thức lớp đặc biệt để truy cập chúng.

+ (HouseholdInventoryManager*) sharedManager; {
    static dispatch_once_t onceQueue;
    static HouseholdInventoryManager* _sharedInstance;

    // dispatch_once is guaranteed to only be executed once in the
    // lifetime of the application
    dispatch_once(&onceQueue, ^{
        _sharedInstance = [[self alloc] init];
    });
    return _sharedInstance;
}

Bây giờ chúng ta đã hiểu thế nào là một singleton, hãy thảo luận về cách một singleton phù hợp với mô hình quan sát viên. Mẫu quan sát được sử dụng cho một đối tượng để đáp ứng với những thay đổi của đối tượng khác. Trong kịch bản thứ hai, chúng tôi có bốn bộ điều khiển chế độ xem khác nhau, tất cả đều muốn biết về các thay đổi đối với dữ liệu cơ bản. "Dữ liệu cơ bản" phải thuộc về một trường hợp duy nhất, một singleton. "Biết về những thay đổi" được thực hiện bằng cách quan sát những thay đổi được thực hiện cho người độc thân.

Ứng dụng kiểm kê nhà sẽ có một phiên bản duy nhất của một lớp được thiết kế để quản lý danh sách các mục kiểm kê. Người quản lý sẽ quản lý một bộ sưu tập các vật dụng gia đình. Sau đây là định nghĩa lớp cho trình quản lý dữ liệu:

#import <Foundation/Foundation.h>

@class JGCHouseholdInventoryItem;

@interface HouseholdInventoryManager : NSObject
/*!
 The global singleton for accessing application data
 */
+ (HouseholdInventoryManager*) sharedManager;


- (NSArray *) entireHouseholdInventory;
- (NSArray *) luxuryItems;
- (NSArray *) nonInsuredItems;

- (void) addHouseholdItemToHomeInventory:(JGCHouseholdInventoryItem*)item;
- (void) editHouseholdItemInHomeInventory:(JGCHouseholdInventoryItem*)item;
- (void) deleteHoueholdItemFromHomeInventory:(JGCHouseholdInventoryItem*)item;
@end

Khi bộ sưu tập các mặt hàng tồn kho trong nhà thay đổi, bộ điều khiển xem cần được biết về sự thay đổi này. Định nghĩa lớp ở trên không làm rõ điều này sẽ xảy ra như thế nào. Chúng ta cần phải theo mô hình quan sát viên. Các bộ điều khiển xem phải chính thức quan sát sharedManager. Có hai cách để quan sát đối tượng khác:

  • Quan sát giá trị khóa (KVO)
  • NSNotificationCenter.

Trong kịch bản hai, chúng tôi không có một thuộc tính duy nhất của Hộ gia đình có thể quan sát được bằng cách sử dụng KVO. Vì chúng tôi không có một thuộc tính duy nhất có thể quan sát dễ dàng, nên mẫu quan sát viên, trong trường hợp này, phải được triển khai bằng NSNotificationCenter. Mỗi trong số bốn bộ điều khiển chế độ xem sẽ đăng ký thông báo và sharedManager sẽ gửi thông báo đến trung tâm thông báo khi thích hợp. Người quản lý kho không cần biết bất cứ điều gì về bộ điều khiển xem hoặc phiên bản của bất kỳ lớp nào khác có thể quan tâm để biết khi nào bộ sưu tập các mặt hàng tồn kho thay đổi; NSNotificationCenter sẽ chăm sóc các chi tiết triển khai này. Bộ điều khiển xem chỉ cần đăng ký thông báo và trình quản lý dữ liệu chỉ cần đăng thông báo.

Nhiều lập trình viên mới bắt đầu tận dụng thực tế là luôn có chính xác một Đại biểu ứng dụng trong suốt vòng đời của ứng dụng, có thể truy cập toàn cầu. Các lập trình viên mới bắt đầu sử dụng thực tế này để nhét các đối tượng và chức năng vào appDelegate như một sự thuận tiện để truy cập từ bất kỳ nơi nào khác trong ứng dụng. Chỉ vì AppDelegate là một singleton không có nghĩa là nó sẽ thay thế tất cả các singleton khác. Đây là một thực tiễn kém vì nó đặt quá nhiều gánh nặng lên một lớp, phá vỡ các thực hành hướng đối tượng tốt. Mỗi lớp nên có một vai trò rõ ràng dễ dàng được giải thích, thường chỉ bằng tên của lớp.

Bất cứ khi nào Đại biểu ứng dụng của bạn bắt đầu trở nên cồng kềnh, hãy bắt đầu loại bỏ chức năng vào các singletons. Ví dụ, không nên để lại Core Data Stack trong AppDelegate mà thay vào đó nên đặt trong lớp riêng của nó, một lớp coreDataManager.

Người giới thiệu


41

OP không đề cập đến các bộ điều khiển xem nhưng rất nhiều câu trả lời, tôi muốn tìm hiểu về những tính năng mới của LLVM cho phép làm cho điều này dễ dàng hơn khi muốn truyền dữ liệu từ bộ điều khiển xem này sang bộ điều khiển khác nhận được một số kết quả trở lại.

Phân biệt bảng phân cảnh, khối ARC và LLVM giúp tôi dễ dàng hơn bao giờ hết. Một số câu trả lời ở trên đã đề cập đến bảng phân cảnh và phân biệt nhưng vẫn dựa vào phái đoàn. Xác định các đại biểu chắc chắn hoạt động nhưng một số người có thể thấy việc chuyển con trỏ hoặc khối mã dễ dàng hơn.

Với UINavigators và segues, có nhiều cách dễ dàng truyền thông tin đến bộ điều khiển phụ và lấy lại thông tin. ARC làm cho việc truyền con trỏ đến những thứ xuất phát từ NSObjects trở nên đơn giản, vì vậy nếu bạn muốn bộ điều khiển phụ trợ thêm / thay đổi / sửa đổi một số dữ liệu cho bạn, hãy chuyển nó thành một con trỏ có thể thay đổi. Các khối giúp thực hiện các hành động dễ dàng vì vậy nếu bạn muốn bộ điều khiển phụ trợ gọi một hành động trên bộ điều khiển cấp cao hơn của bạn, hãy chuyển nó thành một khối. Bạn xác định khối để chấp nhận bất kỳ số lượng đối số có ý nghĩa với bạn. Bạn cũng có thể thiết kế API để sử dụng nhiều khối nếu phù hợp với mọi thứ hơn.

Dưới đây là hai ví dụ tầm thường của keo segue. Đầu tiên là đơn giản hiển thị một tham số được truyền cho đầu vào, thứ hai cho đầu ra.

// Prepare the destination view controller by passing it the input we want it to work on
// and the results we will look at when the user has navigated back to this controller's view.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    [[segue destinationViewController]

     // This parameter gives the next controller the data it works on.
     segueHandoffWithInput:self.dataForNextController

     // This parameter allows the next controller to pass back results
     // by virtue of both controllers having a pointer to the same object.
     andResults:self.resultsFromNextController];
}

Ví dụ thứ hai này cho thấy việc chuyển một khối gọi lại cho đối số thứ hai. Tôi thích sử dụng các khối vì nó giữ các chi tiết có liên quan gần nhau trong nguồn - nguồn cấp cao hơn.

// Prepare the destination view controller by passing it the input we want it to work on
// and the callback when it has done its work.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    [[segue destinationViewController]

     // This parameter gives the next controller the data it works on.
     segueHandoffWithInput:self.dataForNextController

     // This parameter allows the next controller to pass back results.
     resultsBlock:^(id results) {
         // This callback could be as involved as you like.
         // It can use Grand Central Dispatch to have work done on another thread for example.
        [self setResultsFromNextController:results];
    }];
}

41

Truyền dữ liệu trở lại từ ViewContoder 2 (đích) đến viewContaptor 1 (Nguồn) là điều thú vị hơn. Giả sử bạn sử dụng StoryBoard đó là tất cả những cách tôi tìm ra:

  • Đại biểu
  • Thông báo
  • Mặc định của người dùng
  • Người độc thân

Những người đã được thảo luận ở đây rồi.

Tôi thấy có nhiều cách hơn:

-Sử dụng khối gọi lại:

sử dụng nó trong prepareForSeguephương thức trong VC1

NextViewController *destinationVC = (NextViewController *) segue.destinationViewController;
[destinationVC setDidFinishUsingBlockCallback:^(NextViewController *destinationVC)
{
    self.blockLabel.text = destination.blockTextField.text;
}];

-Sử dụng bảng phân cảnh Unwind (Thoát)

Thực hiện một phương thức với đối số UIStoryboardSegue trong VC 1, như thế này:

-(IBAction)UnWindDone:(UIStoryboardSegue *)segue { }

Trong câu chuyệnBoard móc nút "trở lại" vào nút Thoát màu xanh lá cây (Unwind) của vc. Bây giờ bạn có một segue "quay lại" để bạn có thể sử dụng thuộc tính DestinationViewControll trong phần chuẩn bị của VC2 và thay đổi bất kỳ thuộc tính nào của VC1 trước khi nó quay trở lại.

  • Một tùy chọn khác về sử dụng bảng phân cảnh Undwind (Thoát) - bạn có thể sử dụng phương thức bạn đã viết trong VC1

    -(IBAction)UnWindDone:(UIStoryboardSegue *)segue {
        NextViewController *nextViewController = segue.sourceViewController;
        self.unwindLabel.text = nextViewController.unwindPropertyPass;
    } 

    Và trong phần chuẩn bị của VC1, bạn có thể thay đổi bất kỳ thuộc tính nào bạn muốn chia sẻ.

Trong cả hai tùy chọn thư giãn, bạn có thể đặt thuộc tính thẻ của nút và kiểm tra nó trong phần chuẩn bị.

Hy vọng tôi đã thêm một cái gì đó vào cuộc thảo luận.

:) Chúc mừng.


40

Có nhiều phương pháp để chia sẻ dữ liệu.

  1. Bạn luôn có thể chia sẻ dữ liệu bằng cách sử dụng NSUserDefaults. Đặt giá trị bạn muốn chia sẻ liên quan đến khóa bạn chọn và nhận giá trị từ NSUserDefaultliên kết với khóa đó trong trình điều khiển chế độ xem tiếp theo.

    [[NSUserDefaults standardUserDefaults] setValue:value forKey:key]
    [[NSUserDefaults standardUserDefaults] objectForKey:key]
  2. Bạn chỉ có thể tạo một tài sản trong viewcontrollerA. Tạo một đối tượng viewcontrollerAtrong viewcontrollerBvà gán giá trị mong muốn cho thuộc tính đó.

  3. Bạn cũng có thể tạo đại biểu tùy chỉnh cho việc này.


30
Mục đích tiêu biểu của NSUserDefaults là lưu trữ các tùy chọn người dùng vẫn tồn tại giữa các lần thực thi ứng dụng, vì vậy mọi thứ được lưu trữ ở đây sẽ ở lại trừ khi được gỡ bỏ rõ ràng. Thật là một ý tưởng tồi khi sử dụng điều này để truyền thông tin giữa các bộ điều khiển xem (hoặc bất kỳ đối tượng nào khác) trong một ứng dụng.
Jose González

30

Nếu bạn muốn truyền dữ liệu từ bộ điều khiển này sang bộ điều khiển khác, hãy thử mã này

FirstViewControll.h

@property (nonatomic, retain) NSString *str;

SecondViewControll.h

@property (nonatomic, retain) NSString *str1;

FirstViewControll.m

- (void)viewDidLoad
   {
     // message for the second SecondViewController
     self.str = @"text message";

     [super viewDidLoad];
   }

-(IBAction)ButtonClicked
 {
   SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil];
   secondViewController.str1 = str;
  [self.navigationController pushViewController:secondViewController animated:YES];
 }

29

Đây là một câu trả lời rất cũ và đây là mô hình chống, xin vui lòng sử dụng các đại biểu. Không sử dụng phương pháp này !!

1. Tạo phiên bản của Trình điều khiển xem thứ nhất trong Trình điều khiển xem thứ hai và tạo thuộc tính của nó @property (nonatomic,assign).

2. Chỉ định SecondviewControllerthể hiện của bộ điều khiển khung nhìn này.

2. Khi bạn hoàn thành thao tác lựa chọn, sao chép mảng vào Trình điều khiển xem đầu tiên, Khi bạn hủy bỏ Chế độ xem thứ hai, FirstView sẽ giữ Dữ liệu mảng.

Hi vọng điêu nay co ich.


2
Tôi không tin rằng đây là cách chính xác để đi vì nó tạo ra một liên kết rất rõ ràng giữa các bộ điều khiển xem. Không thực sự gắn bó với MVC.
Matt Giá

1
Nếu bạn muốn tuân thủ nghiêm ngặt MVC, hãy sử dụng NSNotificationCenter, một phương thức có thể được gọi từ ViewControllA đến ViewContoderB, hãy kiểm tra xem điều này có thể giúp bạn
kaar3k

28

Tôi đã tìm kiếm giải pháp này trong một thời gian dài, Atlast tôi đã tìm thấy nó. Trước hết, khai báo tất cả các đối tượng trong tệp SecondViewControll.h của bạn như

@interface SecondViewController: UIviewController 
{
    NSMutableArray *myAray;
    CustomObject *object;
}

Bây giờ trong tệp thực hiện của bạn phân bổ bộ nhớ cho các đối tượng như thế này

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
     self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
     if (self) 
     {
         // Custom initialization
         myAray=[[NSMutableArray alloc] init];
         object=[[CustomObject alloc] init];
     }
     return self;
}

Bây giờ bạn đã phân bổ bộ nhớ cho Arrayvà đối tượng. bây giờ bạn có thể lấp đầy bộ nhớ đó trước khi đẩy nóViewController

Chuyển đến SecondViewControll.h của bạn và viết hai phương thức

-(void)setMyArray:(NSArray *)_myArray;
-(void)setMyObject:(CustomObject *)_myObject;

trong tập tin thực hiện, bạn có thể thực hiện chức năng

-(void)setMyArray:(NSArray *)_myArray
{
     [myArra addObjectsFromArray:_myArray];
}
-(void)setMyObject:(CustomObject *)_myObject
{
     [object setCustomObject:_myObject];
}

hy vọng rằng bạn CustomObjectphải có một hàm setter với nó.

bây giờ công việc cơ bản của bạn đã xong. đi đến nơi mà bạn muốn đẩy SecondViewControllervà làm những việc sau đây

SecondViewController *secondView= [[SecondViewController alloc] initWithNibName:@"SecondViewController " bundle:[NSBundle MainBundle]] ;
[secondView setMyArray:ArrayToPass];
[secondView setMyObject:objectToPass];
[self.navigationController pushViewController:secondView animated:YES ];

Hãy cẩn thận cho những lỗi chính tả.


24

Đây không phải là cách để làm điều đó, bạn nên sử dụng các đại biểu, tôi sẽ giả sử chúng ta có hai bộ điều khiển xem ViewControll1 và ViewContoder2 và điều này kiểm tra là trong cái đầu tiên và khi trạng thái của nó thay đổi, bạn muốn làm gì đó trong ViewContoder2, để đạt được điều đó theo cách thích hợp, bạn nên làm như sau:

Thêm một tệp mới vào tệp dự án của bạn (Giao thức Objective-C) - Mới, bây giờ hãy đặt tên cho nó là ViewControll1Delegate hoặc bất cứ điều gì bạn muốn và viết chúng giữa các lệnh @interface và @end

@optional

- (void)checkStateDidChange:(BOOL)checked;

Bây giờ, hãy truy cập ViewControll2.h và thêm

#import "ViewController1Delegate.h"

sau đó thay đổi định nghĩa của nó thành

@interface ViewController2: UIViewController<ViewController1Delegate>

Bây giờ, hãy truy cập ViewControll2.m và bên trong phần thực hiện thêm:

- (void)checkStateDidChange:(BOOL)checked {
     if (checked) {
           // Do whatever you want here
           NSLog(@"Checked");
     }
     else {
           // Also do whatever you want here
           NSLog(@"Not checked");
     }
}

Bây giờ, hãy truy cập ViewControll1.h và thêm thuộc tính sau:

@property (weak, nonatomic) id<ViewController1Delegate> delegate; 

Bây giờ nếu bạn đang tạo ViewContoder1 bên trong ViewControll2 sau một số sự kiện, thì bạn nên thực hiện theo cách này bằng các tệp NIB:

ViewController1* controller = [[NSBundle mainBundle] loadNibNamed:@"ViewController1" owner:self options:nil][0];
controller.delegate = self;
[self presentViewController:controller animated:YES completion:nil];

Bây giờ bạn đã thiết lập xong, bất cứ khi nào bạn phát hiện sự kiện kiểm tra đã thay đổi trong ViewControll1, tất cả những gì bạn phải làm là bên dưới

[delegate checkStateDidChange:checked]; // You pass here YES or NO based on the check state of your control

Vui lòng cho tôi biết nếu có bất cứ điều gì không rõ ràng nếu tôi không hiểu đúng câu hỏi của bạn.


23

Nếu bạn muốn gửi dữ liệu từ một đến một viewContoder khác, đây là một cách để nó:

Giả sử chúng ta có viewControllers: viewControllA và viewControllB

Bây giờ trong viewControllB.h

@interface viewControllerB : UIViewController {

  NSString *string;
  NSArray *array;

}

- (id)initWithArray:(NSArray)a andString:(NSString)s;

Trong viewControllB.m

#import "viewControllerB.h"

@implementation viewControllerB

- (id)initWithArray:(NSArray)a andString:(NSString)s {

   array = [[NSArray alloc] init];
   array = a;

   string = [[NSString alloc] init];
   string = s;

}

Trong viewControllA.m

#import "viewControllerA.h"
#import "viewControllerB.h"

@implementation viewControllerA

- (void)someMethod {

  someArray = [NSArray arrayWithObjects:@"One", @"Two", @"Three", nil];
  someString = [NSString stringWithFormat:@"Hahahahaha"];

  viewControllerB *vc = [[viewControllerB alloc] initWithArray:someArray andString:someString];

  [self.navigationController pushViewController:vc animated:YES];
  [vc release];

}

Vì vậy, đây là cách bạn có thể chuyển dữ liệu từ viewControllA sang viewControllB mà không cần đặt bất kỳ ủy nhiệm nào. ;)


1
Tôi đã thử sử dụng mã ur trong dự án của mình, nhưng tôi không thể nhận được các giá trị trong viewcontrollB. Bạn có thể cho tôi biết những gì có thể là vấn đề?
Bộ giải mã X

1
@Ajitthala Bạn có thể dán mã của mình vào một câu hỏi mới không? Tôi sẽ cố gắng giải quyết vấn đề của bạn. :)
Aniruddh Joshi

1
Có sai không khi sử dụng các phương thức init và chỉ cần làm một cái gì đó như vcB.opes = @ "asdf" từ viewcontroll A?
khanh.tran.vinh

1
@ khanh.tran.vinh Phụ thuộc vào việc bạn có đang sử dụng ARC hay không.
Aniruddh Joshi

21

Tôi biết đây là một chủ đề bị đánh đập nhưng đối với những người muốn trả lời câu hỏi này bằng một câu SWift và muốn có một ví dụ cơ bản, đây là phương pháp chuyển dữ liệu của tôi nếu bạn đang sử dụng một segue để đi xung quanh.

Nó tương tự như trên nhưng không có các nút, nhãn và như vậy. Chỉ đơn giản là truyền dữ liệu từ chế độ xem này sang chế độ xem tiếp theo.

Thiết lập Storyboard

Có ba phần.

  1. Người gửi
  2. Phân đoạn
  3. Người nhận

Đây là một bố cục xem rất đơn giản với một sự khác biệt giữa chúng.


Bố cục xem rất đơn giản.  Lưu ý: Không có bộ điều khiển điều hướng


Đây là thiết lập cho người gửi


Người gửi


Đây là thiết lập cho người nhận.


Người nhận


Cuối cùng, thiết lập cho segue.


Mã định danh phân đoạn


Bộ điều khiển xem

Chúng tôi đang giữ đơn giản điều này để không có nút bấm, không phải hành động, chúng tôi chỉ đơn giản là di chuyển dữ liệu từ người gửi đến người nhận khi ứng dụng tải và sau đó xuất giá trị được truyền tới bàn điều khiển.

Trang này lấy giá trị được tải ban đầu và chuyển nó đi cùng.

import UIKit


class ViewControllerSender: UIViewController {

    // THE STUFF - put some info into a variable
    let favoriteMovie = "Ghost Busters"

    override func viewDidAppear(animated: Bool) {
        // PASS IDENTIFIER - go to the recieving view controller.
        self.performSegueWithIdentifier("goToReciever", sender: self)
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

        //GET REFERENCE - ...to the receiver view.
        var viewControllerReceiver = segue.destinationViewController as? ViewControllerReceiver

        //PASS STUFF - pass the variable along to the target.
        viewControllerReceiver!.yourFavMovie = self.favoriteMovie

    }

}

Trang này chỉ gửi giá trị của biến đến bàn điều khiển khi tải. Đến thời điểm này, bộ phim yêu thích của chúng tôi nên nằm trong biến đó.

import UIKit

class ViewControllerReceiver: UIViewController {

    //Basic empty variable waiting for you to pass in your fantastic favorite movie.
    var yourFavMovie = ""

    override func viewDidLoad() {
        super.viewDidLoad()

        //And now we can view it in the console.
        println("The Movie is \(self.yourFavMovie)")

    }   
}

Đó là cách bạn có thể giải quyết nó nếu bạn muốn sử dụng một segue và bạn không có các trang của mình dưới bộ điều khiển điều hướng.

Khi nó được chạy, nó sẽ tự động chuyển sang chế độ xem của người nhận và chuyển giá trị từ người gửi sang người nhận, hiển thị giá trị trong bàn điều khiển.

Ghost Busters là một người cổ điển.


19

Trong trường hợp của tôi, tôi đã sử dụng một lớp singleton có thể hoạt động như một đối tượng toàn cầu cho phép truy cập dữ liệu từ hầu hết mọi nơi trong ứng dụng. Điều đầu tiên là xây dựng một lớp học đơn. Vui lòng tham khảo trang " Đơn vị Objective-C của tôi trông như thế nào? " Và những gì tôi đã làm để làm cho đối tượng có thể truy cập toàn cầu chỉ đơn giản là nhập nó appName_Prefix.pchđể áp dụng câu lệnh nhập trong mỗi lớp. Để truy cập đối tượng này và sử dụng, tôi chỉ cần thực hiện phương thức lớp để trả về thể hiện được chia sẻ, chứa các biến riêng của nó


Đây là câu trả lời chính xác. Chỉ cần sử dụng một singleton là "mô hình". Lưu ý rằng như Caleb nói "mô hình cho ứng dụng của bạn có thể đơn giản như một chuỗi các chuỗi" . Điều quan trọng cần lưu ý là thực hiện một singleton trong Swift, thực sự không quan trọng . (Rất đơn giản, nó thậm chí không đáng nhắc đến ở đây - chỉ cần google.) Đối với các lập trình viên mới, điều đáng để hiểu là làm cho một người độc thân từng là một nỗi đau thực sự ở mông . Tuy nhiên, singletons hoàn toàn tập trung vào lập trình iOS - mọi thứ Apple làm là một singleton. Đó là lý do tại sao Apple cuối cùng đã biến nó thành trtvial (trong Swift) để tạo ra các singletons đúng cách.
Fattie

1
Tuy nhiên, lưu ý rằng những ngày này (2016+) "mọi thứ đều là chế độ xem container trong iOS". Mỗi điều bạn làm trên màn hình, bạn tạo một chế độ xem nhỏ. Việc xem các chuỗi lượt xem "lên và xuống" của tham chiếu là khá đơn giản (mặc dù Apple sẽ làm điều đó dễ dàng hơn trong tương lai) và dù sao bạn cũng làm điều này cho hầu hết mọi lượt xem của container. Vì vậy, nếu bạn đã làm điều đó bằng mọi cách - bạn có câu trả lời; không cần một singleton. Chế độ xem container giới thiệu ... stackoverflow.com/a/23403979/294884
Fattie

19

Swift 5

Vâng Matt Price trả lời là hoàn toàn tốt đẹp cho truyền dữ liệu nhưng tôi sẽ viết lại nó, trong Latest Swift phiên bản vì tôi tin rằng các lập trình viên mới thấy nó bỏ thách thức do Cú pháp mới và phương pháp / khuôn khổ, như bài gốc là trong Objective-C.

Có nhiều tùy chọn để truyền dữ liệu giữa các bộ điều khiển xem.

  1. Sử dụng Bộ điều khiển Điều hướng Đẩy
  2. Sử dụng phân đoạn
  3. Sử dụng đại biểu
  4. Sử dụng Trình quan sát thông báo
  5. Sử dụng khối

Tôi sẽ viết lại logic của anh ấy trong Swift với iOS Framework mới nhất


Truyền dữ liệu qua bộ điều khiển điều hướng Đẩy : Từ ViewControllA đến ViewContoderB

Bước 1. Khai báo biến trong ViewControllB

var isSomethingEnabled = false

Bước 2. In biến trong phương thức ViewDidLoad của ViewContoderB

override func viewDidLoad() {
        super.viewDidLoad()
        //Print value received through segue, navigation push
        print("Value of 'isSomethingEnabled' from ViewControllerA : ", isSomethingEnabled)
    }

Bước 3. Trong ViewControllA Truyền dữ liệu trong khi đẩy qua Bộ điều khiển điều hướng

if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
        viewControllerB.isSomethingEnabled = true
        if let navigator = navigationController {
            navigator.pushViewController(viewControllerB, animated: true)
        }
    }

Vì vậy, đây là mã hoàn chỉnh cho:

ViewControllA

import UIKit

class ViewControllerA: UIViewController  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //MARK:Passing Data through Navigation PushViewController
    @IBAction func goToViewControllerB(_ sender: Any) {

        if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
            viewControllerB.isSomethingEnabled = true
            if let navigator = navigationController {
                navigator.pushViewController(viewControllerB, animated: true)
            }
        }
    }
}

ViewControllB

import UIKit

class ViewControllerB: UIViewController {

    //MARK:  - Variable for Passing Data through Navigation push   
    var isSomethingEnabled = false

    override func viewDidLoad() {
        super.viewDidLoad()
        //Print value received through navigation push
        print("Value of 'isSomethingEnabled' from ViewControllerA : ", isSomethingEnabled)
    }
}

Truyền dữ liệu qua phân đoạn : Từ ViewControllA đến ViewContoderB

Bước 1. Tạo Segue từ ViewContoderA đến ViewContoderB và đưa ra Định danh = showDetailSegue trong Storyboard như hiển thị bên dưới

nhập mô tả hình ảnh ở đây

Bước 2. Trong ViewControllB Khai báo một tên khả thi có tên làS SomethingEnables và in giá trị của nó.

Bước 3. Trong ViewControllA, vượt qua giá trị isS SomethingEnables trong khi truyền Segue

Vì vậy, đây là mã hoàn chỉnh cho:

ViewControllA

import UIKit

class ViewControllerA: UIViewController  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //MARK:  - - Passing Data through Segue  - - 
    @IBAction func goToViewControllerBUsingSegue(_ sender: Any) {
        performSegue(withIdentifier: "showDetailSegue", sender: nil)
    }

    //Segue Delegate Method
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if (segue.identifier == "showDetailSegue") {
            let controller = segue.destination as? ViewControllerB
            controller?.isSomethingEnabled = true//passing data
        }
    }
}

ViewControllB

import UIKit

class ViewControllerB: UIViewController {
    var isSomethingEnabled = false

    override func viewDidLoad() {
        super.viewDidLoad()
        //Print value received through segue
        print("Value of 'isSomethingEnabled' from ViewControllerA : ", isSomethingEnabled)
    }
}

Truyền dữ liệu qua Delegate : Từ ViewControllB đến ViewControllA

Bước 1. Khai báo giao thức ViewContoderBDelegate trong tệp ViewControllB nhưng bên ngoài lớp

protocol ViewControllerBDelegate: NSObjectProtocol {

    // Classes that adopt this protocol MUST define
    // this method -- and hopefully do something in
    // that definition.
    func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?)
}

Bước 2. Khai báo thể hiện biến đại biểu trong ViewContoderB

var delegate: ViewControllerBDelegate?

Bước 3. Gửi dữ liệu cho đại biểu bên trong phương thức viewDidLoad của ViewContoderB

delegate?.addItemViewController(self, didFinishEnteringItem: "Data for ViewControllerA")

Bước 4. Xác nhận ViewControllBDelegate trong ViewControllA

class ViewControllerA: UIViewController, ViewControllerBDelegate  {
// to do
}

Bước 5. Xác nhận rằng bạn sẽ triển khai ủy nhiệm trong ViewControllA

if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
            viewControllerB.delegate = self//confirming delegate
            if let navigator = navigationController {
                navigator.pushViewController(viewControllerB, animated: true)
            }
        }

Bước 6. Thực hiện phương thức ủy nhiệm để nhận dữ liệu trong ViewControllA

func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?) {
        print("Value from ViewControllerB's Delegate", item!)
    }

Vì vậy, đây là mã hoàn chỉnh cho:

ViewControllA

import UIKit

class ViewControllerA: UIViewController, ViewControllerBDelegate  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //Delegate method
    func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?) {
        print("Value from ViewControllerB's Delegate", item!)
    }

    @IBAction func goToViewControllerForDelegate(_ sender: Any) {

        if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
            viewControllerB.delegate = self
            if let navigator = navigationController {
                navigator.pushViewController(viewControllerB, animated: true)
            }
        }
    }
}

ViewControllB

import UIKit

//Protocol decleare
protocol ViewControllerBDelegate: NSObjectProtocol {
    // Classes that adopt this protocol MUST define
    // this method -- and hopefully do something in
    // that definition.
    func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?)
}

class ViewControllerB: UIViewController {
    var delegate: ViewControllerBDelegate?

    override func viewDidLoad() {
        super.viewDidLoad()
        //MARK:  - - - -  Set Data for Passing Data through Delegate  - - - - - -
        delegate?.addItemViewController(self, didFinishEnteringItem: "Data for ViewControllerA")
    }
}

Truyền dữ liệu qua Trình quan sát thông báo : Từ ViewControllB đến ViewControllA

Bước 1. Đặt và Đăng dữ liệu trong Trình quan sát thông báo trong ViewContoderB

let objToBeSent = "Test Message from Notification"
        NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: objToBeSent)

Bước 2. Thêm Trình quan sát thông báo trong ViewControllA

NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)

Bước 3. Nhận giá trị dữ liệu Thông báo trong ViewControllA

@objc func methodOfReceivedNotification(notification: Notification) {
        print("Value of notification : ", notification.object ?? "")
    }

Vì vậy, đây là mã hoàn chỉnh cho:

ViewControllA

import UIKit

class ViewControllerA: UIViewController{

    override func viewDidLoad() {
        super.viewDidLoad()

        // add observer in controller(s) where you want to receive data
        NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)
    }

    //MARK: Method for receiving Data through Post Notification 
    @objc func methodOfReceivedNotification(notification: Notification) {
        print("Value of notification : ", notification.object ?? "")
    }
}

ViewControllB

import UIKit

class ViewControllerB: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        //MARK:Set data for Passing Data through Post Notification
        let objToBeSent = "Test Message from Notification"
        NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: objToBeSent)
    }
}

Truyền dữ liệu qua khối : Từ ViewControllB đến ViewContoderA

Bước 1. Khai báo khối trong ViewControllB

var ủy quyềnCompletionBlock: ((Bool) -> ())? = {_ in}

Bước 2. Đặt dữ liệu trong khối trong ViewControllB

if authorizationCompletionBlock != nil
        {
            authorizationCompletionBlock!(true)
        }

Bước 3. Nhận dữ liệu khối trong ViewControllA

//Receiver Block
                controller!.authorizationCompletionBlock = { isGranted in
                    print("Data received from Block is :", isGranted)
                }

Vì vậy, đây là mã hoàn chỉnh cho:

ViewControllA

import UIKit

class ViewControllerA: UIViewController  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //MARK:Method for receiving Data through Block
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if (segue.identifier == "showDetailSegue") {
                let controller = segue.destination as? ViewControllerB
                controller?.isSomethingEnabled = true

                //Receiver Block
                controller!.authorizationCompletionBlock = { isGranted in
                    print("Data received from Block is :", isGranted)
                }
            }
        }
}

ViewControllB

import UIKit

class ViewControllerB: UIViewController {

    //MARK:Variable for Passing Data through Block
    var authorizationCompletionBlock:((Bool)->())? = {_ in}

    override func viewDidLoad() {
        super.viewDidLoad()

        //MARK:Set data for Passing Data through Block
        if authorizationCompletionBlock != nil
        {
            authorizationCompletionBlock!(true)
        }
    }
}

Bạn có thể tìm thấy Ứng dụng mẫu hoàn chỉnh tại GitHub của tôi Vui lòng cho tôi biết nếu bạn có bất kỳ câu hỏi nào về vấn đề này.


18

Truyền dữ liệu giữa FirstViewContaptor sang SecondViewControll như bên dưới

Ví dụ:

Giá trị chuỗi FirstViewControll như

StrFirstValue = @"first";

vì vậy chúng ta có thể chuyển giá trị này trong lớp thứ hai bằng cách sử dụng bước dưới đây

1> Chúng ta cần tạo đối tượng chuỗi trong tệp SecondViewControll.h

NSString *strValue;

2> Cần khai báo thuộc tính như bên dưới khai báo trong tệp .h

@property (strong, nonatomic)  NSString *strSecondValue;

3> Cần tổng hợp giá trị đó trong tệp FirstViewControll.m bên dưới khai báo tiêu đề

@synthesize strValue;

và trong FirstViewControll.h:

@property (strong, nonatomic)  NSString *strValue;

4> Trong FirstViewControll, từ phương thức nào chúng ta điều hướng đến chế độ xem thứ hai, vui lòng viết mã bên dưới trong phương thức đó.

SecondViewController *secondView= [[SecondViewController alloc]     
initWithNibName:@"SecondViewController " bundle:[NSBundle MainBundle]];

[secondView setStrSecondValue:StrFirstValue];

[self.navigationController pushViewController:secondView animated:YES ];

Sau khi ở trong SecondViewContaptor, làm thế nào để bạn chuyển dữ liệu trở lại FirstViewControll?
bruno

18

Tôi hiện đang đóng góp cho một giải pháp nguồn mở cho vấn đề này thông qua một dự án có tên MCViewFactory, có thể được tìm thấy ở đây:

https://github.com/YetiHQ/manticore-iosviewfactory

Ý tưởng này bắt chước mô hình ý định của Android, sử dụng một nhà máy toàn cầu để quản lý chế độ xem bạn đang xem và sử dụng "ý định" để chuyển đổi và truyền dữ liệu giữa các chế độ xem. Tất cả các tài liệu đều có trên trang github, nhưng đây là một số điểm nổi bật:

Bạn thiết lập tất cả các chế độ xem của mình trong các tệp .XIB và đăng ký chúng trong đại biểu ứng dụng, trong khi khởi tạo nhà máy.

// Register activities

MCViewFactory *factory = [MCViewFactory sharedFactory];

// the following two lines are optional. 
[factory registerView:@"YourSectionViewController"]; 

Bây giờ, trong VC của bạn, bất cứ khi nào bạn muốn chuyển sang một VC mới và truyền dữ liệu, bạn tạo một ý định mới và thêm dữ liệu vào từ điển của nó (yetInstanceState). Sau đó, chỉ cần đặt mục đích hiện tại của nhà máy:

MCIntent* intent = [MCIntent intentWithSectionName:@"YourSectionViewController"];
[intent setAnimationStyle:UIViewAnimationOptionTransitionFlipFromLeft];
[[intent savedInstanceState] setObject:@"someValue" forKey:@"yourKey"];
[[intent savedInstanceState] setObject:@"anotherValue" forKey:@"anotherKey"];
// ...
[[MCViewModel sharedModel] setCurrentSection:intent];

Tất cả các chế độ xem phù hợp với điều này cần phải là các lớp con của MCViewControll, cho phép bạn ghi đè phương thức onResume: mới, cho phép bạn truy cập vào dữ liệu bạn đã truyền vào.

-(void)onResume:(MCIntent *)intent {
    NSObject* someValue = [intent.savedInstanceState objectForKey:@"yourKey"];
    NSObject* anotherValue = [intent.savedInstanceState objectForKey:@"anotherKey"];

    // ...

    // ensure the following line is called, especially for MCSectionViewController
    [super onResume:intent];
}

Hy vọng một số bạn tìm thấy giải pháp này hữu ích / thú vị.


Sau đó, tất cả các đối tượng điều khiển có thể nhận / đặt tất cả các từ điển đã đăng ký trong bất kỳ phạm vi nào? Downvote này.
Itachi

15

Tạo thuộc tính tiếp theo view controller .hvà xác định getter và setter.

Thêm phần này propertyvào NextVC.h trên nextVC

@property (strong, nonatomic) NSString *indexNumber;

Thêm vào

@synthesize indexNumber; trong NextVC.m

Và cuối cùng

NextVC *vc=[[NextVC alloc]init];

vc.indexNumber=@"123";

[self.navigationController vc animated:YES];

11

Có rất nhiều cách để làm điều này và điều quan trọng là chọn đúng. Có lẽ một trong những quyết định kiến ​​trúc lớn nhất nằm ở cách mã mô hình sẽ được chia sẻ hoặc truy cập trong suốt ứng dụng.

Tôi đã viết một bài đăng trên blog về điều này một thời gian trước: Chia sẻ Mã mẫu . Đây là một bản tóm tắt ngắn gọn:

Chia sẻ dữ liệu

Một cách tiếp cận là chia sẻ các con trỏ tới các đối tượng mô hình giữa các bộ điều khiển xem.

  • Lặp lại lực lượng mạnh mẽ trên các bộ điều khiển xem (trong Bộ điều hướng hoặc Thanh điều khiển Tab) để đặt dữ liệu
  • Đặt dữ liệu trong readyForSegue (nếu bảng phân cảnh) hoặc init (nếu lập trình)

Vì chuẩn bị cho segue là phổ biến nhất ở đây là một ví dụ:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    var next = segue.destinationViewController as NextViewController
    next.dataSource = dataSource
}

Truy cập độc lập

Một cách tiếp cận khác là xử lý một màn hình đầy dữ liệu cùng một lúc và thay vì ghép các bộ điều khiển chế độ xem với nhau, mỗi bộ điều khiển chế độ xem với nguồn dữ liệu duy nhất mà chúng có thể độc lập.

Cách phổ biến nhất tôi từng thấy điều này được thực hiện là một ví dụ đơn lẻ . Vì vậy, nếu đối tượng singleton của bạn là DataAccessbạn có thể thực hiện các thao tác sau trong phương thức viewDidLoad của UIViewControll:

func viewDidLoad() {
    super.viewDidLoad()
    var data = dataAccess.requestData()
}

Có các công cụ bổ sung cũng giúp truyền dữ liệu:

  • Quan sát giá trị khóa
  • NSNotify
  • Dữ liệu cốt lõi
  • NSFetchedResultsCont kiểm
  • Nguồn dữ liệu

Dữ liệu cốt lõi

Điều hay ho về Core Data là nó có các mối quan hệ nghịch đảo. Vì vậy, nếu bạn muốn cung cấp cho NotesViewControll đối tượng ghi chú bạn có thể bởi vì nó sẽ có mối quan hệ nghịch đảo với một thứ khác như sổ ghi chép. Nếu bạn cần dữ liệu trên sổ ghi chép trong NotesViewControll, bạn có thể sao lưu biểu đồ đối tượng bằng cách thực hiện như sau:

let notebookName = note.notebook.name

Đọc thêm về điều này trong bài viết trên blog của tôi: Mã mô hình chia sẻ


10

NewsViewControll

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
  [tbl_View deselectRowAtIndexPath:indexPath animated:YES];
  News *newsObj = [newstitleArr objectAtIndex:indexPath.row];
  NewsDetailViewController *newsDetailView = [[NewsDetailViewController alloc] initWithNibName:@"NewsDetailViewController" bundle:nil];

  newsDetailView.newsHeadlineStr = newsObj.newsHeadline;

  [self.navigationController pushViewController:newsDetailView animated:YES];
}

NewsDetailViewCont điều khiển.h

@interface NewsDetailViewController : UIViewController
@property(nonatomic,retain) NSString *newsHeadlineStr;
@end

NewsDetailViewContoder.m

@synthesize newsHeadlineStr;

10

Ủy quyền là giải pháp duy nhất để thực hiện các thao tác đó khi bạn đang sử dụng tệp .xib tuy nhiên tất cả các câu trả lời được mô tả ở trên là dành storyboardcho các tệp .xibs bạn cần sử dụng ủy quyền. đó là giải pháp duy nhất bạn có thể.

Một giải pháp khác là sử dụng mẫu lớp singleton khởi tạo nó một lần và sử dụng nó trong toàn bộ ứng dụng của bạn.


10

nếu bạn muốn truyền dữ liệu từ ViewControlerOne sang ViewControllTwo hãy thử những điều này ..

làm những điều này trong ViewControlerOne.h

 @property (nonatomic, strong) NSString *str1;

thực hiện những điều này trong ViewControllTwo.h

 @property (nonatomic, strong) NSString *str2;

Tổng hợp str2 trong ViewControllTwo.m

@interface ViewControllerTwo ()
@end
@implementation ViewControllerTwo
@synthesize str2;

làm những việc này trong ViewControlerOne.m

 - (void)viewDidLoad
 {
   [super viewDidLoad];

  // Data or string you wants to pass in ViewControllerTwo..
  self.str1 = @"hello world";

 }

trên các nút bấm sự kiện làm điều này ..

-(IBAction)ButtonClicked
{ //Navigation on buttons click event from ViewControlerOne to ViewControlerTwo with transferring data or string..
  ViewControllerTwo *objViewTwo=[self.storyboard instantiateViewControllerWithIdentifier:@"ViewControllerTwo"];
  obj.str2=str1;
  [self.navigationController pushViewController: objViewTwo animated:YES];
}

thực hiện những điều này trong ViewControllTwo.m

- (void)viewDidLoad
{
 [super viewDidLoad];
  NSLog(@"%@",str2);
}

10

Bạn có thể lưu dữ liệu trong Đại biểu ứng dụng để truy cập nó trên các bộ điều khiển xem trong ứng dụng của bạn. Tất cả bạn phải làm là tạo một phiên bản chia sẻ của đại biểu ứng dụng

AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;

Ví dụ

nếu bạn khai báo NSArray object *arrayXYZthì bạn có thể truy cập nó trong bất kỳ trình điều khiển xem nào bằng cáchappDelegate.arrayXYZ


Đây là phương pháp được lựa chọn cho hackathon
Hai Feng Kao

9

Nếu bạn muốn gửi dữ liệu từ một đến một viewContoder khác, đây là một cách để nó:

Giả sử chúng ta có viewControllers: ViewControll và NewViewControll.

trong ViewControll.h

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
{
    IBOutlet UITextField *mytext1,*mytext2,*mytext3,*mytext4;
}

@property (nonatomic,retain) IBOutlet UITextField *mytext1,*mytext2,*mytext3,*mytext4;

-(IBAction)goToNextScreen:(id)sender;

@end

trong ViewControll.m

#import "ViewController.h"

#import "NewViewController.h"

@implementation ViewController
@synthesize mytext1,mytext2,mytext3,mytext4;

-(IBAction)goToNextScreen:(id)sender
{
    NSArray *arr = [NSArray arrayWithObjects:mytext1.text,mytext2.text,mytext3.text,mytext4.text, nil];


    NewViewController *newVc = [[NewViewController alloc] initWithNibName:@"NewViewController" bundle:nil];

    newVc.arrayList = arr;

    [self.navigationController pushViewController:newVc animated:YES];

}

Trong NewViewControll.h

#import <UIKit/UIKit.h>

@interface NewViewController : UITableViewController
{
    NSArray *arrayList;

    NSString *name,*age,*dob,*mobile;

}

@property(nonatomic, retain)NSArray *arrayList;

@end

Trong NewViewControll.m

#import "NewViewController.h"

#import "ViewController.h"

@implementation NewViewController
@synthesize arrayList;

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

    // Return the number of sections.
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

    // Return the number of rows in the section.
    return [arrayList count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil)
    {
         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];      
    }
    // Configure the cell...
    cell.textLabel.text = [arrayList objectAtIndex:indexPath.row];
    return cell;


}

@end

Vì vậy, theo cách này chúng ta có thể truyền dữ liệu từ một bộ điều khiển khung nhìn sang bộ điều khiển khung nhìn khác ...


8

Tôi thích ý tưởng về các đối tượng Mô hình và các đối tượng Mock dựa trên NSProxy để cam kết hoặc loại bỏ dữ liệu nếu những gì người dùng chọn có thể bị hủy.

Thật dễ dàng để truyền dữ liệu xung quanh vì nó là một đối tượng hoặc một vài đối tượng và nếu bạn nói rằng bộ điều khiển UINavestionContaptor, bạn có thể giữ tham chiếu đến mô hình bên trong và tất cả các bộ điều khiển xem đẩy có thể truy cập trực tiếp từ bộ điều khiển điều hướng.


8

Tôi đã thấy rất nhiều người phức tạp hơn bằng cách sử dụng didSelectRowAtPathphương pháp này. Tôi đang sử dụng Core Data trong ví dụ của mình.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

    //this solution is for using Core Data
    YourCDEntityName * value = (YourCDEntityName *)[[self fetchedResultsController] objectAtIndexPath: indexPath];

    YourSecondViewController * details = [self.storyboard instantiateViewControllerWithIdentifier:@"nameOfYourSecondVC"];//make sure in storyboards you give your second VC an identifier

    //Make sure you declare your value in the second view controller
    details.selectedValue = value;

    //Now that you have said to pass value all you need to do is change views
    [self.navigationController pushViewController: details animated:YES];

}

4 dòng mã bên trong phương thức và bạn đã hoàn thành.


6

Có nhiều câu trả lời cho câu hỏi này cung cấp nhiều cách khác nhau để thực hiện giao tiếp điều khiển xem thực sự có hiệu quả, nhưng tôi không thấy nơi nào được đề cập là cách nào thực sự tốt nhất để sử dụng và cách nào nên tránh.

Trong thực tế, theo tôi chỉ có một vài giải pháp được đề xuất:

  • Để truyền dữ liệu về phía trước:
    • ghi đè prepare(for:sender:)phương thức UIViewControllerkhi sử dụng bảng phân cảnh và phân biệt
    • truyền dữ liệu qua bộ khởi tạo hoặc thông qua các thuộc tính khi thực hiện chuyển đổi bộ điều khiển xem mã thông qua
  • Để truyền dữ liệu ngược
    • cập nhật trạng thái chia sẻ ứng dụng (mà bạn có thể chuyển tiếp giữa các bộ điều khiển xem với một trong các phương pháp trên)
    • đoàn sử dụng
    • sử dụng một segue thư giãn

Các giải pháp tôi khuyên KHÔNG nên sử dụng:

  • Tham khảo bộ điều khiển trước trực tiếp thay vì sử dụng ủy quyền
  • Chia sẻ dữ liệu thông qua một singleton
  • Truyền dữ liệu qua đại biểu ứng dụng
  • Chia sẻ dữ liệu thông qua mặc định của người dùng
  • Truyền dữ liệu qua thông báo

Các giải pháp này, mặc dù hoạt động trong thời gian ngắn, giới thiệu quá nhiều phụ thuộc sẽ cắt xén kiến ​​trúc của ứng dụng và tạo ra nhiều vấn đề hơn sau này.

Đối với những người quan tâm, tôi đã viết một số bài viết đề cập đến những điểm này sâu hơn và làm nổi bật những nhược điểm khác nhau:

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.