Szukaj…


Korzystanie z segmentów (przekazywanie danych do przodu)

Aby przekazać dane z bieżącego kontrolera widoku do następnego nowego kontrolera widoku (nie poprzedniego kontrolera widoku) przy użyciu segu, najpierw utwórz segregację z identyfikatorem w odpowiedniej scenorysie. Zastąp metodę prepareForSegue bieżącego kontrolera prepareForSegue . Wewnątrz metody sprawdź segment utworzony właśnie przez jego identyfikator. Rzuć kontroler widoku docelowego i przekaż mu dane, ustawiając właściwości na kontrolerze widoku w dół.

Ustawienie identyfikatora dla segue:

Przypisuje inspektora do segue

Segmenty można wykonywać programowo lub przy użyciu zdarzenia akcji przycisku ustawionego w serii ujęć za pomocą kombinacji klawiszy Ctrl + Przeciągnij do kontrolera widoku docelowego. W razie potrzeby możesz wywoływać segue programowo, używając identyfikatora segue w kontrolerze widoku:

Cel C

- (void)showDetail {
    [self performSegueWithIdentifier:@"showDetailingSegue" sender:self];        
}

Szybki

func showDetail() {
    self.performSegue(withIdentifier: "showDetailingSegue", sender: self)
}

Można skonfigurować ładunek segue w przesłoniętej wersji metody prepareForSegue . Można ustawić wymagane właściwości przed załadowaniem docelowego kontrolera widoku.

Cel C

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

Szybki

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "showDetailingSegue" {
        let controller = segue.destinationViewController as! DetailViewController
        controller.isDetailingEnabled = true
    }    
}

DetailViewController to nazwa drugiego kontrolera widoku, a isDetailingEnabled to zmienna publiczna w tym kontrolerze widoku.

Aby rozwinąć ten wzorzec, można traktować metodę publiczną na DetailViewController jako pseudoinicjalizator, aby pomóc w inicjalizacji wymaganych zmiennych. Spowoduje to samodzielne dokumentowanie zmiennych, które należy ustawić w DetailViewController bez konieczności czytania jego kodu źródłowego. Jest to również przydatne miejsce do ustawienia domyślnych.

Cel C

- (void)initVC:(BOOL *)isDetailingEnabled {
    self.isDetailingEnabled = isDetailingEnabled
}

Szybki

func initVC(isDetailingEnabled: Bool) {
    self.isDetailingEnabled = isDetailingEnabled
}

Korzystanie ze wzoru delegowania (przekazywanie danych z powrotem)

Aby przekazać dane z bieżącego kontrolera widoku z powrotem do poprzedniego kontrolera widoku, możesz użyć wzorca delegowania.

wprowadź opis zdjęcia tutaj

W tym przykładzie założono, że utworzono segue w Konstruktorze interfejsów i ustawiono identyfikator segue na showSecondViewController . Punkty sprzedaży i działania muszą być również podłączone do nazw w poniższym kodzie.

Kontroler pierwszego widoku

Kod kontrolera First View to

Szybki

class FirstViewController: UIViewController, DataEnteredDelegate {

    @IBOutlet weak var label: UILabel!
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showSecondViewController", let secondViewController = segue.destinationViewController as? SecondViewController  {
            secondViewController.delegate = self
        }
    }

    // required method of our custom DataEnteredDelegate protocol
    func userDidEnterInformation(info: String) {
        label.text = info
        navigationController?.popViewControllerAnimated(true)
    }
}

Cel C

@interface FirstViewController : UIViewController <DataEnteredDelegate>
@property (weak, nonatomic) IBOutlet UILabel *label;
@end

@implementation FirstViewController
- (void)viewDidLoad {
    [super viewDidLoad];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    SecondViewController *secondViewController = segue.destinationViewController;
    secondViewController.delegate = self;

}
-(void)userDidEnterInformation:(NSString *)info {
    _label.text = info
    [self.navigationController popViewControllerAnimated:YES];
}
@end

Zwróć uwagę na użycie naszego niestandardowego protokołu DataEnteredDelegate .

Drugi widok kontrolera i protokołu

Kod drugiego kontrolera widoku to

Szybki

// protocol used for sending data back
protocol DataEnteredDelegate: class {
    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?
    
    @IBOutlet weak var textField: UITextField!

    @IBAction func sendTextBackButton(sender: AnyObject) {
        
        // call this method on whichever class implements our delegate protocol (the first view controller)
        delegate?.userDidEnterInformation(textField.text ?? "")
    }
}

Cel C

@protocol DataEnteredDelegate <NSObject>
-(void)userDidEnterInformation:(NSString *)info;
@end

@interface SecondViewController : UIViewController 
@property (nonatomic) id <DataEnteredDelegate> delegate;
@property (weak, nonatomic) IBOutlet UITextField *textField;
@end

@implementation SecondViewController
- (void)viewDidLoad {
    [super viewDidLoad];
}

- (IBAction) sendTextBackButton:(id)sender{
    [_delegate userDidEnterInformation:textField.text];
}
@end

Zauważ, że protocol znajduje się poza klasą View Controller.

Przekazywanie danych do tyłu za pomocą cofania do segregacji

W przeciwieństwie do segue, który pozwala przekazywać dane „do przodu” z bieżącego kontrolera widoku do docelowego kontrolera widoku:

(VC1) -> (VC2)

Korzystając z funkcji „odprężenia”, można zrobić odwrotnie, przekazać dane z docelowego lub bieżącego kontrolera widoku do jego kontrolera prezentacji:

(VC1) <- (VC2)

UWAGA : Zwróć uwagę, że użycie odprężania pozwala najpierw przekazać dane, a następnie bieżący kontroler widoku (VC2) zostanie zwolniony.

Oto jak to zrobić:

Najpierw musisz dodać następującą deklarację do kontrolera widoku prezentującego (VC1), który jest kontrolerem widoku, do którego chcemy przekazać dane:

@IBAction func unwindToPresentingViewController(segue:UIStoryboardSegue)

Ważne jest, aby użyć prefiksu unwind , „informuje” Xcode, że jest to metoda odwijania, dająca możliwość użycia jej również w serii ujęć.

Następnie musisz zaimplementować metodę, wygląda ona prawie tak samo jak rzeczywisty segue:

@IBAction func unwindToPresentingViewController(segue:UIStoryboardSegue)
{
    if segue.identifier == "YourCustomIdentifer"
    {
        if let VC2 = segue.sourceViewController as? VC2
        {
            //    Your custom code in here to access VC2 class member
        }

Teraz masz 2 opcje wywoływania połączeń relaksacyjnych:

  1. Możesz „na self.performSegueWithIdentifier("YourCustomIdentifier", sender: self) kodować” wywoływać: self.performSegueWithIdentifier("YourCustomIdentifier", sender: self) który zrobi dla ciebie odpoczynek, ilekroć wykonasz performSegueWithIdentifier .
  2. Możesz połączyć metodę odwijania za pomocą storyboard z obiektem „Wyjdź”: ctrl + przeciągnij przycisk, który chcesz wywołać metodę odwijania, do obiektu „Wyjdź”:

wprowadź opis zdjęcia tutaj

Zwolnij, a będziesz mieć możliwość wyboru niestandardowej metody odwijania:

wprowadź opis zdjęcia tutaj

Przekazywanie danych za pomocą zamknięć (przekazywanie danych z powrotem)

Zamiast używać wzorca delegowania , który dzieli implementację na różne części klasy UIViewController , można nawet używać closures do przekazywania danych w przód iw tył. Zakładając, że korzystasz z UIStoryboardSegue , w metodzie prepareForSegue możesz łatwo skonfigurować nowy kontroler w jednym kroku

final class DestinationViewController: UIViewController {
    var onCompletion: ((success: Bool) -> ())?

    @IBAction func someButtonTapped(sender: AnyObject?) {
        onCompletion?(success: true)
    }
}

final class MyViewController: UIViewController {
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    
        guard let destinationController = segue.destinationViewController as? DestinationViewController else { return }
    
        destinationController.onCompletion = { success in
            // this will be executed when `someButtonTapped(_:)` will be called
            print(success)
        }
    }
}

Jest to przykład użycia i lepiej go używać w Swift, składnia bloku Objective-C nie jest tak łatwa, aby kod był bardziej czytelny

Wykorzystanie zamknięcia (bloku) oddzwaniania przekazującego dane z powrotem

ten temat jest klasycznym zagadnieniem w rozwoju iOS, a jego rozwiązanie jest różne, jak pokazano już w innym przykładzie. W tym przykładzie pokażę inny typowy codzienny sposób użycia: przekazywanie danych przy użyciu closure poprzez dostosowanie przykładu delegate pattern na tej stronie do closure wywołania zwrotnego!

jedna metoda jest lepsza niż delegate pattern - zamiast rozdzielić kod konfiguracyjny w dwa różne miejsca (spójrz na przykład delegowania na tej stronie, prepareForSegue , userDidEnterInformation ), zamiast gromadzić je razem (tylko w prepareForSegue , pokażę to)

Zacznij od drugiego kontrolera widoku

musimy dowiedzieć się, jak korzystać z wywołania zwrotnego, a następnie możemy to napisać, dlatego zaczynamy od drugiego kontrolera widoku, ponieważ tam właśnie używamy wywołania zwrotnego: kiedy otrzymaliśmy nowe wprowadzanie tekstu, wywołujemy nasze wywołanie zwrotne, używając parametru wywołania zwrotnego jako medium aby przekazać dane z powrotem do pierwszego ViewController, zauważ, że powiedziałem, używając parametru wywołania zwrotnego, jest to bardzo ważne, nowicjusze (tak jak ja) zawsze przeoczają to i nie wiedzą, od czego zacząć poprawnie pisać zamknięcie wywołania zwrotnego

więc w tym przypadku wiemy, że nasze wywołanie zwrotne przyjmuje tylko jeden parametr: tekst, a jego typ to String , zadeklarujmy go i ustawmy jako właściwość, ponieważ musimy wypełnić go z naszego pierwszego kontrolera widoku

Po prostu komentuję całą część delegate i zachowuję ją do porównania

class SecondViewController: UIViewController {

    //weak var delegate: DataEnteredDelegate? = nil
    var callback: ((String?)->())?
    
    @IBOutlet weak var textField: UITextField!

    @IBAction func sendTextBackButton(sender: AnyObject) {
        
        //delegate?.userDidEnterInformation(textField.text!)
        callback?(input.text)
        
        self.navigationController?.popViewControllerAnimated(true)
    }
}

Zakończ pierwszy widok kontrolera

wszystko, co musisz zrobić, to przekazać zamknięcie oddzwonienia, a my skończymy, zamknięcie wykona dla nas przyszłą pracę, ponieważ już skonfigurowaliśmy to w drugim kontrolerze widoku

zobacz, jak skraca nasz kod w porównaniu do delegate pattern

//no more DataEnteredDelegate
class FirstViewController: UIViewController {

    @IBOutlet weak var label: UILabel!
    
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "showSecondViewController" {
            let secondViewController = segue.destinationViewController as! SecondViewController
            //secondViewController.delegate = self
            secondViewController.callback = { text in self.label.text = text }
        }
    }

    // required method of our custom DataEnteredDelegate protocol
    //func userDidEnterInformation(info: String) {
    //    label.text = info
    //}
}

i na koniec, być może ktoś z was będzie zdezorientowany tym, że przekazujemy dane (w tym przypadku zamknięcie) tylko w jeden sposób, od pierwszego kontrolera widoku do drugiego, bez bezpośredniego powrotu z drugiego kontrolera widoku, jak możemy uznać to za narzędzie komunikacji? może naprawdę powinieneś go uruchomić i sam to udowodnić, powiem tylko, że to parametr , to parametr zamknięcia wywołania zwrotnego, który przekazuje dane z powrotem!

Przypisując właściwość (Przekazywanie danych do przodu)

Możesz przekazać dane bezpośrednio, przypisując właściwość następnego kontrolera widoku przed jego wypchnięciem lub zaprezentowaniem.

class FirstViewController: UIViewController {

    func openSecondViewController() {

        // Here we initialize SecondViewController and set the id property to 492
        let secondViewController = SecondViewController()
        secondViewController.id = 492

        // Once it was assign we now push or present the view controller
        present(secondViewController, animated: true, completion: nil)
    }

}

class SecondViewController: UIViewController {
    
    var id: Int?

    override func viewDidLoad() {
        super.viewDidLoad()

        // Here we unwrapped the id and will get the data from the previous view controller.
        if let id = id {
            print("Id was set: \(id)")
        }
    }
}


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow