To pytanie wydaje się być bardzo popularne tutaj w stackoverflow, więc pomyślałem, że postaram się udzielić lepszej odpowiedzi, aby pomóc osobom rozpoczynającym pracę w świecie iOS, takim jak ja.
Mam nadzieję, że ta odpowiedź jest wystarczająco jasna, aby ludzie mogli ją zrozumieć i że niczego mi nie umknęło.
Przekazywanie danych do przodu
Przekazywanie danych do kontrolera widoku z innego kontrolera widoku. Zastosowałbyś tę metodę, gdybyś chciał przekazać obiekt / wartość z jednego kontrolera widoku do innego kontrolera widoku, który możesz naciskać na stos nawigacji.
W tym przykładzie będziemy mieli ViewControllerA
iViewControllerB
Aby przekazać BOOL
wartość od ViewControllerA
do ViewControllerB
, wykonajmy następujące czynności.
w ViewControllerB.h
utwórz właściwość dlaBOOL
@property (nonatomic, assign) BOOL isSomethingEnabled;
w ViewControllerA
musisz powiedzieć o tym, ViewControllerB
więc użyj
#import "ViewControllerB.h"
Następnie, gdzie chcesz załadować widok np. didSelectRowAtIndex
lub niektóre IBAction
musisz ustawić właściwość ViewControllerB
przed wypchnięciem jej na stos nawigacyjny.
ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
viewControllerB.isSomethingEnabled = YES;
[self pushViewController:viewControllerB animated:YES];
Spowoduje to ustawienie isSomethingEnabled
w ViewControllerB
celu BOOL
wartości YES
.
Przekazywanie danych za pomocą segmentów
Jeśli używasz Storyboardów, najprawdopodobniej używasz sekwensów i będziesz potrzebować tej procedury, aby przekazać dane dalej. Jest to podobne do powyższego, ale zamiast przekazywać dane przed naciśnięciem kontrolera widoku, używasz metody o nazwie
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
Aby przekazać BOOL
od ViewControllerA
do ViewControllerB
, zrobilibyśmy następujące:
w ViewControllerB.h
utwórz właściwość dlaBOOL
@property (nonatomic, assign) BOOL isSomethingEnabled;
w ViewControllerA
musisz powiedzieć o tym, ViewControllerB
więc użyj
#import "ViewControllerB.h"
Utwórz segregację od ViewControllerA
do ViewControllerB
na storyboardzie i podaj jej identyfikator, w tym przykładzie nazwiemy go"showDetailSegue"
Następnie musimy dodać metodę, ViewControllerA
która jest wywoływana, gdy wykonywany jest jakikolwiek segment, dlatego musimy wykryć, który segment został wywołany, a następnie coś zrobić. W naszym przykładzie sprawdzimy, "showDetailSegue"
a jeśli zostanie to wykonane, przekażemy naszą BOOL
wartość doViewControllerB
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:@"showDetailSegue"]){
ViewControllerB *controller = (ViewControllerB *)segue.destinationViewController;
controller.isSomethingEnabled = YES;
}
}
Jeśli masz widoki osadzone w kontrolerze nawigacyjnym, musisz nieco zmienić powyższą metodę na następującą
-(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;
}
}
Spowoduje to ustawienie isSomethingEnabled
w ViewControllerB
celu BOOL
wartości YES
.
Przekazywanie danych z powrotem
Aby przekazać dane z powrotem ViewControllerB
do ViewControllerA
, musisz użyć protokołów i delegatów lub bloków , ten ostatni może być używany jako luźno powiązany mechanizm oddzwaniania.
W tym celu zostaniemy ViewControllerA
delegatem ViewControllerB
. Pozwala ViewControllerB
to odesłać wiadomość z powrotem, ViewControllerA
umożliwiając nam odesłanie danych z powrotem.
Aby ViewControllerA
zostać delegatem ViewControllerB
, musi być zgodny z ViewControllerB
protokołem, który musimy określić. Mówi to, ViewControllerA
które metody musi wdrożyć.
W ViewControllerB.h
, poniżej #import
, ale powyżej @interface
określasz protokół.
@class ViewControllerB;
@protocol ViewControllerBDelegate <NSObject>
- (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
@end
następnie nadal w ViewControllerB.h
musisz ustawić delegate
właściwość i dokonać syntezyViewControllerB.m
@property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
W ViewControllerB
wywołujemy komunikat o tym, delegate
kiedy otwieramy kontroler widoku.
NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
[self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
To tyle ViewControllerB
. Teraz w ViewControllerA.h
, powiedz, ViewControllerA
aby zaimportować ViewControllerB
i dostosować się do protokołu.
#import "ViewControllerB.h"
@interface ViewControllerA : UIViewController <ViewControllerBDelegate>
W ViewControllerA.m
realizować w następujący sposób z naszym protokołem
- (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
{
NSLog(@"This was returned from ViewControllerB %@",item);
}
Przed viewControllerB
przekazaniem do stosu nawigacyjnego musimy powiedzieć, ViewControllerB
że ViewControllerA
jest jego delegatem, w przeciwnym razie otrzymamy błąd.
ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
viewControllerB.delegate = self
[[self navigationController] pushViewController:viewControllerB animated:YES];
Bibliografia
- Używanie delegowania do komunikowania się z innymi kontrolerami widoku w Przewodniku programowania kontrolera widoku
- Deleguj wzór
NSNotification center
To kolejny sposób przekazywania danych.
// 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];
Przekazywanie danych z jednej klasy do drugiej (klasą może być dowolny kontroler, menedżer sieci / sesji, podklasa UIView lub dowolna inna klasa)
Bloki są funkcjami anonimowymi.
Ten przykład przekazuje dane z kontrolera B do kontrolera A.
zdefiniuj blok
@property void(^selectedVoucherBlock)(NSString *); // in ContollerA.h
dodaj moduł obsługi bloku (detektor)
tam, gdzie potrzebujesz wartości (na przykład potrzebujesz odpowiedzi API w ControllerA lub potrzebujesz danych ContorllerB w A)
// in ContollerA.m
- (void)viewDidLoad {
[super viewDidLoad];
__unsafe_unretained typeof(self) weakSelf = self;
self.selectedVoucherBlock = ^(NSString *voucher) {
weakSelf->someLabel.text = voucher;
};
}
Przejdź do kontrolera B.
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
ControllerB *vc = [storyboard instantiateViewControllerWithIdentifier:@"ControllerB"];
vc.sourceVC = self;
[self.navigationController pushViewController:vc animated:NO];
blok ognia
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:
(NSIndexPath *)indexPath {
NSString *voucher = vouchersArray[indexPath.row];
if (sourceVC.selectVoucherBlock) {
sourceVC.selectVoucherBlock(voucher);
}
[self.navigationController popToViewController:sourceVC animated:YES];
}
Kolejny przykład roboczy dla bloków
@class ViewControllerB;
powyższą definicję @protocol? Bez niego pojawia się błąd „Oczekiwany typ” na ViewControllerB w wierszu:- (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
w@protocol
deklaracjiNavigationController
, musisz użyć[self.navigationController pushViewController:viewController animated:YES];
zamiast tego[self pushViewController:viewControllerB animated:YES];
Szybki
Istnieje mnóstwo tonów wyjaśnień tutaj i wokół StackOverflow, ale jeśli jesteś początkującym, próbując zdobyć coś podstawowego do pracy, spróbuj obejrzeć ten samouczek YouTube (dzięki temu mogłem w końcu zrozumieć, jak to zrobić).
Przekazywanie danych do następnego kontrolera widoku
Poniżej znajduje się przykład oparty na filmie. Pomysł polega na przekazaniu ciągu znaków z pola tekstowego w Pierwszym kontrolerze widoku do etykiety w drugim kontrolerze widoku.
Utwórz układ scenorysu w Konstruktorze interfejsów. Aby zrobić segue, wystarczy Controlkliknąć przycisk i przeciągnąć do kontrolera drugiego widoku.
Kontroler pierwszego widoku
Kod kontrolera First View to
Kontroler drugiego widoku
Kod drugiego kontrolera widoku to
Nie zapomnij
UITextField
iUILabel
.Przekazywanie danych z powrotem do poprzedniego kontrolera widoku
Aby przekazać dane z drugiego kontrolera widoku do pierwszego kontrolera widoku, użyj protokołu i delegata . Ten film jest jednak bardzo przejrzystym przykładem tego procesu:
Poniżej znajduje się przykład oparty na filmie (z kilkoma modyfikacjami).
Utwórz układ scenorysu w Konstruktorze interfejsów. Ponownie, aby zrobić segue, po prostu Controlprzeciągnij z przycisku do kontrolera drugiego widoku. Ustaw identyfikator segue na
showSecondViewController
. Nie zapomnij także podłączyć gniazdek i działań, używając nazw w poniższym kodzie.Kontroler pierwszego widoku
Kod kontrolera First View to
Zwróć uwagę na użycie naszego niestandardowego
DataEnteredDelegate
protokołu.Drugi widok kontrolera i protokołu
Kod drugiego kontrolera widoku to
Zauważ, że
protocol
jest poza klasą View Controller.Otóż to. Uruchomiona aplikacja powinna być w stanie odesłać dane z drugiego kontrolera widoku do pierwszego.
źródło
secondViewController.delegate = self
to zatem: „Zgadzam się być szefem”. Zobacz tę odpowiedź na inny przykład i więcej wyjaśnień.M w MVC dotyczy „Modelu”, aw paradygmacie MVC rolą klas modeli jest zarządzanie danymi programu. Model jest przeciwieństwem widoku - widok wie, jak wyświetlać dane, ale nie wie nic o tym, co zrobić z danymi, podczas gdy model wie wszystko o tym, jak pracować z danymi, ale nic o tym, jak je wyświetlić. Modele mogą być skomplikowane, ale nie muszą tak być - model aplikacji może być tak prosty, jak tablica ciągów lub słowników.
Rolą kontrolera jest pośredniczenie między widokiem a modelem. Dlatego potrzebują odniesienia do jednego lub więcej obiektów widoku i jednego lub więcej obiektów modelu. Załóżmy, że Twój model to tablica słowników, w której każdy słownik reprezentuje jeden wiersz w tabeli. Widok główny aplikacji wyświetla tę tabelę i może być odpowiedzialny za ładowanie tablicy z pliku. Gdy użytkownik zdecyduje się dodać nowy wiersz do tabeli, stuknie jakiś przycisk, a kontroler utworzy nowy (modyfikowalny) słownik i doda go do tablicy. Aby wypełnić wiersz, kontroler tworzy kontroler widoku szczegółów i nadaje mu nowy słownik. Kontroler widoku szczegółowego wypełnia słownik i zwraca. Słownik jest już częścią modelu, więc nic więcej nie musi się wydarzyć.
źródło
Istnieją różne sposoby odbioru danych do innej klasy w systemie iOS. Na przykład -
NSUserDefaults
- do późniejszego dostępuJednak w przypadku prostego scenariusza przekazania wartości do innej klasy, której alokacji dokonuje się w bieżącej klasie, najbardziej powszechną i preferowaną metodą byłoby bezpośrednie ustawienie wartości po alokacji. Odbywa się to w następujący sposób:
Możemy to zrozumieć za pomocą dwóch kontrolerów - Controller1 i Controller2
Załóżmy, że w klasie Controller1 chcesz utworzyć obiekt Controller2 i przekazać go z przekazywaną wartością typu String. Można to zrobić w następujący sposób:
W implementacji klasy Controller2 pojawi się ta funkcja jako-
Możesz także bezpośrednio ustawić właściwości klasy Controller2 w podobny sposób:
Aby przekazać wiele wartości, możesz użyć wielu parametrów, takich jak:
Lub jeśli potrzebujesz przekazać więcej niż 3 parametry związane ze wspólną funkcją, możesz zapisać wartości do klasy Model i przekazać ten modelObject do następnej klasy
Krótko mówiąc, jeśli chcesz -
Mam nadzieję że to pomoże
źródło
Po dalszych badaniach wydawało się, że Protokoły i delegaci to właściwy / preferowany przez Apple sposób robienia tego.
Skończyło się na tym przykładzie
Udostępnianie danych między kontrolerami widoku a innymi obiektami @ iPhone Dev SDK
Działa dobrze i pozwala mi przekazywać ciąg i tablicę do przodu i do tyłu między moimi widokami.
Dziękuję za twoją pomoc
źródło
Znajduję najprostszą i najbardziej elegancką wersję z przechodzącymi blokami. Nazwijmy kontroler widoku, który czeka na zwrócone dane, na „A”, a kontroler widoku na „B”. W tym przykładzie chcemy uzyskać 2 wartości: pierwszą z Type1 i drugą z Type2.
Zakładając, że używamy Storyboard, pierwszy kontroler ustawia blok zwrotny, na przykład podczas przygotowywania segue:
i kontroler widoku „B” powinien zadeklarować właściwość wywołania zwrotnego BViewController.h:
Niż w pliku implementacyjnym BViewController.m po tym, jak żądamy wartości do zwrócenia, nasze wywołanie zwrotne powinno zostać wywołane:
Jedną rzeczą do zapamiętania jest to, że używanie bloku często musi zarządzać silnymi i __słabymi referencjami, jak wyjaśniono tutaj
źródło
W wielu udzielonych odpowiedziach jest kilka dobrych informacji, ale żadne z nich nie odnosi się w pełni do pytania.
Pytanie dotyczy przekazywania informacji między kontrolerami widoku. Podany konkretny przykład dotyczy przekazywania informacji między widokami, ale biorąc pod uwagę stwierdzoną nowość w systemie iOS, oryginalny plakat prawdopodobnie oznaczał między viewControllers, a nie między widokami (bez żadnego udziału ViewControllers). Wygląda na to, że wszystkie odpowiedzi koncentrują się na dwóch kontrolerach widoku, ale co, jeśli aplikacja ewoluuje i musi wymagać więcej niż dwóch kontrolerów widoku w wymianie informacji?
Oryginalny plakat zapytał także o Singletons i korzystanie z AppDelegate . Na te pytania należy odpowiedzieć.
Aby pomóc każdemu, kto patrzy na to pytanie, kto chce pełnej odpowiedzi, postaram się udzielić jej.
Scenariusze aplikacji
Zamiast mieć wysoce hipotetyczną, abstrakcyjną dyskusję, pomaga mieć na uwadze konkretne zastosowania. Aby pomóc w zdefiniowaniu sytuacji kontrolera dwóch widoków i sytuacji kontrolera więcej niż dwóch widoków, zdefiniuję dwa konkretne scenariusze aplikacji.
Scenariusz pierwszy: maksymalnie dwa kontrolery widoku muszą kiedykolwiek wymieniać informacje. Zobacz schemat pierwszy.
Aplikacja zawiera dwa kontrolery widoku. Istnieje ViewControllerA (formularz wprowadzania danych) i View Controller B (lista produktów). Elementy wybrane na liście produktów muszą pasować do elementów wyświetlanych w polu tekstowym w formularzu wprowadzania danych. W tym scenariuszu ViewControllerA i ViewControllerB muszą komunikować się ze sobą bezpośrednio, a nie z innymi kontrolerami widoku.
Scenariusz drugi : więcej niż dwa kontrolery widoku muszą udostępniać te same informacje. Zobacz diagram drugi.
Aplikacja zawiera cztery kontrolery widoku. Jest to aplikacja oparta na kartach do zarządzania zapasami domowymi. Trzy kontrolery widoków przedstawiają różnie filtrowane widoki tych samych danych:
Za każdym razem, gdy pojedynczy element jest tworzony lub edytowany, musi również zostać zsynchronizowany z innymi kontrolerami widoku. Na przykład, jeśli dodamy łódź w ViewControllerD, ale nie jest ona jeszcze ubezpieczona, to łódź musi pojawić się, gdy użytkownik przejdzie do ViewControllerA (przedmioty luksusowe), a także ViewControllerC (cały asortyment domowy), ale nie wtedy, gdy użytkownik przejdzie do ViewControllerB (Produkty nieubezpieczone). Musimy martwić się nie tylko dodawaniem nowych elementów, ale także usuwaniem elementów (które mogą być dozwolone z dowolnego z czterech kontrolerów widoku) lub edytowaniem istniejących elementów (które mogą być dozwolone z poziomu „formularza Dodaj nowy element”, zmieniając przeznaczenie tego samego do edycji).
Ponieważ wszystkie kontrolery widoku muszą współużytkować te same dane, wszystkie cztery kontrolery widoku muszą pozostać zsynchronizowane, a zatem musi istnieć pewnego rodzaju komunikacja z wszystkimi innymi kontrolerami widoku, ilekroć dowolny pojedynczy kontroler widoku zmienia dane bazowe. Powinno być dość oczywiste, że nie chcemy, aby każdy kontroler widoku komunikował się bezpośrednio ze sobą w tym scenariuszu. Jeśli nie jest to oczywiste, zastanów się, czy mieliśmy 20 różnych kontrolerów widoku (a nie tylko 4). Jak trudne i podatne byłoby na powiadamianie każdego z pozostałych 19 kontrolerów widoku za każdym razem, gdy jeden kontroler widoku dokonał zmiany?
Rozwiązania: delegaci i wzorzec obserwatora oraz singletony
W pierwszym scenariuszu mamy kilka realnych rozwiązań, które dały inne odpowiedzi
W scenariuszu drugim mamy inne realne rozwiązania:
Pojedyncza jest przykładem klasy, który przykładowo jest wystąpienie tylko istnieje podczas jego użytkowania. Singleton bierze swoją nazwę od faktu, że jest to pojedyncza instancja. Zwykle programiści używający singletonów mają specjalne metody dostępu do nich.
Teraz, gdy rozumiemy, czym jest singleton, porozmawiajmy o tym, jak singleton pasuje do wzorca obserwatora. Wzorzec obserwatora służy do tego, aby jeden obiekt reagował na zmiany wprowadzane przez inny obiekt. W drugim scenariuszu mamy czterech różnych kontrolerów widoku, którzy wszyscy chcą wiedzieć o zmianach w podstawowych danych. „Podstawowe dane” powinny należeć do pojedynczej instancji, singletonu. „Wiedzieć o zmianach” dokonuje się, obserwując zmiany dokonane w singletonie.
Aplikacja do inwentaryzacji domowej miałaby jedną instancję klasy zaprojektowanej do zarządzania listą pozycji inwentarza. Kierownik zarządzałby kolekcją artykułów gospodarstwa domowego. Poniżej znajduje się definicja klasy dla menedżera danych:
Kiedy zmienia się kolekcja artykułów gospodarstwa domowego, należy poinformować kontrolerów widoku o tej zmianie. Powyższa definicja klasy nie wyjaśnia, jak to się stanie. Musimy podążać za wzorem obserwatora. Kontrolery widoku muszą formalnie obserwować sharedManager. Istnieją dwa sposoby zaobserwowania innego obiektu:
W scenariuszu drugim nie mamy jednej właściwości HouseholdInventoryManager, którą można zaobserwować za pomocą KVO. Ponieważ nie mamy jednej właściwości, którą można łatwo zaobserwować, wzorzec obserwatora w tym przypadku musi zostać zaimplementowany za pomocą NSNotificationCenter. Każdy z czterech kontrolerów widoku subskrybowałby powiadomienia, a SharedManager wysyłałby powiadomienia do centrum powiadomień, gdy było to właściwe. Menedżer zapasów nie musi nic wiedzieć o kontrolerach widoku ani instancjach innych klas, które mogą być zainteresowane wiedzieć, kiedy zmienia się kolekcja przedmiotów zapasowych; NSNotificationCenter zajmuje się tymi szczegółami implementacji. Kontrolery widoku po prostu subskrybują powiadomienia, a menedżer danych po prostu publikuje powiadomienia.
Wielu początkujących programistów korzysta z faktu, że zawsze jest dokładnie jeden delegat aplikacji w czasie życia aplikacji, który jest ogólnie dostępny. Początkujący programiści wykorzystują ten fakt do umieszczania obiektów i funkcji w aplikacji Delegate jako wygody dostępu z dowolnego miejsca w aplikacji. To, że AppDelegate jest singletonem, nie oznacza, że powinno zastąpić wszystkie inne singletony. Jest to zła praktyka, ponieważ zbytnio obciąża jedną klasę, łamiąc dobre praktyki obiektowe. Każda klasa powinna odgrywać wyraźną rolę, którą można łatwo wyjaśnić, często tylko nazwą klasy.
Za każdym razem, gdy delegat aplikacji zaczyna się wzdęcia, zacznij usuwać funkcje z singletonów. Na przykład stos danych podstawowych nie powinien pozostać w AppDelegate, ale powinien zostać umieszczony we własnej klasie, klasie coreDataManager.
Bibliografia
źródło
OP nie wspominał o kontrolerach widoku, ale robi tak wiele odpowiedzi, że chciałem zapoznać się z tym, co niektóre z nowych funkcji LLVM pozwalają to ułatwić, gdy chcemy przekazać dane z jednego kontrolera widoku do drugiego, a następnie odzyskanie niektórych wyników.
Sekwencje scenorysu, bloki ARC i LLVM sprawiają, że jest to dla mnie łatwiejsze niż kiedykolwiek. Niektóre odpowiedzi powyżej wspomniane scenorysy i sekwencje już były, ale nadal polegały na delegacji. Definiowanie delegatów z pewnością działa, ale niektórym osobom może łatwiej przekazywać wskaźniki lub bloki kodu.
Dzięki UINavigators i segu istnieją proste sposoby przekazywania informacji do kontrolera podrzędnego i odzyskiwania informacji. ARC sprawia, że przekazywanie wskaźników do rzeczy pochodzących z obiektów NSObjects jest proste, więc jeśli chcesz, aby kontroler podrzędny dodał / zmienił / zmodyfikował niektóre dane za ciebie, przekaż go wskaźnikiem do zmiennej instancji. Bloki ułatwiają przekazywanie akcji, więc jeśli chcesz, aby kontroler podrzędny wywoływał akcję na kontrolerze wyższego poziomu, przekaż mu blok. Definiujesz blok, aby akceptować dowolną liczbę argumentów, które mają dla ciebie sens. Możesz również zaprojektować interfejs API, aby używał wielu bloków, jeśli lepiej to pasuje.
Oto dwa trywialne przykłady kleju segue. Pierwszy jest prosty i pokazuje jeden parametr przekazany dla danych wejściowych, drugi dla danych wyjściowych.
Ten drugi przykład pokazuje przekazanie bloku zwrotnego dla drugiego argumentu. Lubię używać bloków, ponieważ utrzymuje odpowiednie szczegóły blisko siebie w źródle - źródle wyższego poziomu.
źródło
Przekazywanie danych z ViewController 2 (miejsce docelowe) do viewController 1 (Źródło) jest bardziej interesującą rzeczą. Zakładając, że używasz storyBoard, oto wszystkie sposoby, w jakie się dowiedziałem:
Te zostały już tutaj omówione.
Odkryłem, że jest więcej sposobów:
-Używanie Block callback:
użyj go w
prepareForSegue
metodzie w VC1-Używanie scenariuszy Rozwiń (Wyjdź)
Zaimplementuj metodę z argumentem UIStoryboardSegue w VC 1, taką jak ta:
W StoryBoard zaczep przycisk „powrót” do zielonego przycisku wyjścia (Unwind) w vc. Teraz masz segment, który „wraca”, więc możesz użyć właściwości destinationViewController w preparForSegue VC2 i zmienić dowolną właściwość VC1, zanim ona wróci.
Inna opcja korzystania z scenariuszy Undwind (Wyjdź) - możesz użyć metody napisanej w VC1
A w narzędziu PrepForSegue VC1 możesz zmienić dowolną właściwość, którą chcesz udostępnić.
W obu opcjach odwijania możesz ustawić właściwość tagu przycisku i zaznaczyć ją w preparForSegue.
Mam nadzieję, że dodałem coś do dyskusji.
:) Twoje zdrowie.
źródło
Istnieje wiele metod udostępniania danych.
Zawsze możesz udostępniać dane za pomocą
NSUserDefaults
. Ustaw wartość, którą chcesz udostępnić w odniesieniu do wybranego klucza i uzyskaj wartość zNSUserDefault
powiązanego z tym kluczem w następnym kontrolerze widoku.Możesz po prostu utworzyć właściwość w
viewcontrollerA
. Utwórz obiektviewcontrollerA
wviewcontrollerB
i przypisz żądaną wartość do tej właściwości.Możesz również utworzyć niestandardowych delegatów w tym celu.
źródło
Jeśli chcesz przekazać dane z jednego kontrolera do drugiego, wypróbuj ten kod
FirstViewController.h
SecondViewController.h
FirstViewController.m
źródło
To jest bardzo stara odpowiedź i jest to anty-wzór, proszę użyć delegatów. Nie używaj tego Podejścia !!
1. Utwórz instancję pierwszego kontrolera widoku w drugim kontrolerze widoku i wprowadź jego właściwość
@property (nonatomic,assign)
.2. Przypisz
SecondviewController
wystąpienie tego kontrolera widoku.2. Po zakończeniu operacji zaznaczania skopiuj tablicę do pierwszego kontrolera widoku, gdy zwolnisz SecondView, FirstView będzie przechowywać dane macierzy.
Mam nadzieję że to pomoże.
źródło
Długo szukałem tego rozwiązania, znalazłem je Atlast. Przede wszystkim zadeklaruj wszystkie obiekty w pliku SecondViewController.h, takie jak
Teraz w pliku implementacji przydziel pamięć dla takich obiektów
Teraz przydzieliłeś pamięć
Array
i obiekt. teraz możesz wypełnić tę pamięć, zanim ją wypchnieszViewController
Przejdź do SecondViewController.h i napisz dwie metody
w pliku implementacji możesz zaimplementować funkcję
spodziewając się, że
CustomObject
musisz mieć z nim funkcję ustawiającą.teraz twoja podstawowa praca jest skończona. przejdź do miejsca, w którym chcesz popchnąć
SecondViewController
i wykonaj następujące czynnościUważaj na błędy ortograficzne.
źródło
Nie jest to sposób, aby to zrobić, powinieneś użyć delegatów, zakładam, że mamy dwa kontrolery widoku ViewController1 i ViewController2, a ta kontrola jest w pierwszym, a gdy jej stan się zmieni, chcesz coś zrobić w ViewController2, aby osiągnąć to we właściwy sposób, należy wykonać następujące czynności:
Dodaj nowy plik do projektu (Protokół Objective-C) -> Nowy, nadaj mu nazwę ViewController1Delegate lub cokolwiek chcesz i napisz je między dyrektywami @interface i @end
Teraz przejdź do ViewController2.h i dodaj
następnie zmień jego definicję na
Teraz przejdź do ViewController2.m i wewnątrz implementacji dodaj:
Teraz przejdź do ViewController1.h i dodaj następującą właściwość:
Teraz, jeśli tworzysz ViewController1 wewnątrz ViewController2 po jakimś zdarzeniu, powinieneś to zrobić w ten sposób, używając plików NIB:
Teraz wszystko jest gotowe, za każdym razem, gdy wykryjesz zdarzenie sprawdzania zmienione w ViewController1, wszystko co musisz zrobić, to:
Powiedz mi, czy jest coś, co nie jest jasne, jeśli nie zrozumiałem twojego pytania poprawnie.
źródło
Jeśli chcesz wysłać dane z jednego do drugiego viewController, oto sposób na to:
Powiedzmy, że mamy viewControllers: viewControllerA i viewControllerB
Teraz w widokuControllerB.h
In viewControllerB.m
In viewControllerA.m
W ten sposób możesz przekazywać dane z viewControllerA do viewControllerB bez ustawiania delegata. ;)
źródło
Wiem, że to pobity temat, ale dla tych, którzy chcą odpowiedzieć na to pytanie za pomocą skosu SWIFT i chcą goły przykład, oto moja metoda przekazywania danych, jeśli używasz segue do poruszania się.
Jest podobny do powyższego, ale bez przycisków, etykiet i tym podobnych. Po prostu przesyłanie danych z jednego widoku do drugiego.
Skonfiguruj Storyboard
Istnieją trzy części.
Jest to bardzo prosty układ widoku z odstępem między nimi.
Oto konfiguracja dla nadawcy
Oto konfiguracja odbiornika.
Wreszcie konfiguracja dla segue.
Wyświetl kontrolery
Utrzymujemy to w prosty sposób, więc nie ma przycisków, a nie akcji, po prostu przenosimy dane od nadawcy do odbiornika, gdy aplikacja się ładuje, a następnie przesyłamy przesłaną wartość do konsoli.
Ta strona przyjmuje początkowo załadowaną wartość i przekazuje ją dalej.
Ta strona po prostu wysyła wartość zmiennej do konsoli podczas ładowania. W tym momencie nasz ulubiony film powinien być w tej zmiennej.
W ten sposób możesz sobie z tym poradzić, jeśli chcesz użyć segue i nie masz stron pod kontrolerem nawigacyjnym.
Po uruchomieniu powinien automatycznie przełączyć się do widoku odbiorcy i przekazać wartość od nadawcy do odbiorcy, wyświetlając wartość w konsoli.
źródło
W moim przypadku użyłem klasy singleton, która może działać jako obiekt globalny, umożliwiający dostęp do danych z niemal każdego miejsca w aplikacji. Pierwszą rzeczą jest zbudowanie klasy singleton. Proszę odnieść się do strony: „ Jak powinien wyglądać mój singleton Objective-C? ”. A co zrobiłem, aby obiekt był dostępny na całym świecie, to po prostu zaimportować go,
appName_Prefix.pch
aby zastosować instrukcję importu w każdej klasie. Aby uzyskać dostęp do tego obiektu i użyć, po prostu zaimplementowałem metodę klasy, aby zwrócić współużytkowaną instancję, która zawiera własne zmienneźródło
Istnieje wiele opcji przekazywania danych między kontrolerami widoku.
Zamierzam przepisać jego logikę w Swift przy użyciu najnowszego systemu iOS
Krok 1. Zadeklaruj zmienną w ViewControllerB
Krok 2. Wydrukuj zmienną w metodzie ViewDidLoad ViewControllerB
Krok 3. W ViewController Przekaż dane podczas przepychania przez kontroler nawigacji
Oto pełny kod dla:
ViewControllerA
ViewControllerB
Krok 1. Utwórz segment z ViewControllerA do ViewControllerB i podaj Identifier = showDetailSegue w Storyboard, jak pokazano poniżej
Krok 2. W ViewControllerB Zadeklaruj wykonalnego o nazwie IsomethingEnabled i wypisz jego wartość.
Krok 3. W ViewControllerA pass jest wartośćSomethingEnabled podczas przekazywania Segue
Oto pełny kod dla:
ViewControllerA
ViewControllerB
Krok 1. Zadeklaruj protokół ViewControllerBDelegate w pliku ViewControllerB, ale poza klasą
Krok 2. Zadeklaruj delegowanie zmiennej wystąpienia w ViewControllerB
Krok 3. Wyślij dane do delegowania wewnątrz metody viewDidLoad ViewControllerB
Krok 4. Potwierdź ViewControllerBDelegate w ViewControllerA
Krok 5. Potwierdź, że wdrożysz delegata w ViewControllerA
Krok 6. Zaimplementuj metodę delegowania do odbierania danych w ViewControllerA
Oto pełny kod dla:
ViewControllerA
ViewControllerB
Krok 1. Ustaw i opublikuj dane w obserwatorze powiadomień w ViewControllerB
Krok 2. Dodaj obserwatora powiadomień w ViewControllerA
Krok 3. Odbierz wartość danych powiadomienia w ViewControllerA
Oto pełny kod dla:
ViewControllerA
ViewControllerB
Krok 1. Zadeklaruj blok w ViewControllerB
var autoryzacjaCompletionBlock: ((Bool) -> ())? = {_ in}
Krok 2. Ustaw dane w bloku w ViewControllerB
Krok 3. Odbierz dane bloku w ViewControllerA
Oto pełny kod dla:
ViewControllerA
ViewControllerB
Kompletną przykładową aplikację można znaleźć na moim GitHub Daj mi znać, jeśli masz jakieś pytania na ten temat.
źródło
Przekazywanie danych między FirstViewController do SecondViewController jak poniżej
Na przykład:
FirstViewController Wartość ciągu jako
więc możemy przekazać tę wartość do drugiej klasy, używając poniższego kroku
1> Musimy utworzyć skrzynkę obiektu łańcuchowego w pliku SecondViewController.h
2> Konieczność zadeklarowania właściwości jak poniżej poniżej deklaracji w pliku .h
3> Potrzebujesz zsyntetyzować tę wartość w pliku FirstViewController.m poniżej deklaracji nagłówka
oraz w FirstViewController.h:
4> W FirstViewController, z której metody przechodzimy do drugiego widoku, napisz poniżej kod w tej metodzie.
źródło
Obecnie wnoszę wkład w rozwiązanie tego problemu typu open source poprzez projekt o nazwie MCViewFactory, który można znaleźć tutaj:
https://github.com/YetiHQ/manticore-iosviewfactory
Chodzi o to, aby naśladować intentyczny paradygmat Androida, używając globalnej fabryki do zarządzania widokiem, na który patrzysz, i używając „intencji” do przełączania i przekazywania danych między widokami. Cała dokumentacja znajduje się na stronie github, ale oto kilka najważniejszych informacji:
Wszystkie widoki ustawiasz w plikach .XIB i rejestrujesz je w aplikacji delegowanej podczas inicjowania fabryki.
Teraz w swoim VC, za każdym razem, gdy chcesz przejść do nowego VC i przekazywać dane, tworzysz nowe zamiary i dodajesz dane do słownika (saveInstanceState). Następnie ustaw aktualny cel fabryki:
Wszystkie widoki zgodne z tym muszą być podklasami MCViewController, które pozwalają zastąpić nową metodę onResume:, umożliwiając dostęp do przekazanych danych.
Mam nadzieję, że niektórzy z was uważają to rozwiązanie za przydatne / interesujące.
źródło
Utwórz właściwość na następny
view controller .h
i zdefiniuj getter i setter.Dodaj to
property
w NextVC.h na nextVCDodaj
@synthesize indexNumber;
w NextVC.mI ostatni
źródło
Istnieje wiele sposobów na zrobienie tego i ważne jest, aby wybrać właściwy. Prawdopodobnie jedna z największych decyzji architektonicznych dotyczy sposobu udostępniania lub uzyskiwania dostępu do kodu modelu w aplikacji.
Napisałem o tym post na blogu: Udostępnianie kodu modelu . Oto krótkie podsumowanie:
Udostępnione dane
Jednym z podejść jest współdzielenie wskaźników do obiektów modelu między kontrolerami widoku.
Ponieważ przygotowanie do segue jest najczęstszym przykładem jest tutaj:
Niezależny dostęp
Innym podejściem jest obsługiwanie ekranu pełnego danych na raz i zamiast sprzęgania kontrolerów widoku ze sobą łączy każdy kontroler widoku z pojedynczym źródłem danych, do którego mogą uzyskać dostęp niezależnie.
Najczęstszym sposobem, w jaki to widziałem, jest instancja singletona . Jeśli
DataAccess
więc byłby to twój obiekt singletonu, możesz wykonać następujące czynności w metodzie viewDidLoad UIViewController:Istnieją dodatkowe narzędzia, które pomagają również przekazywać dane:
Podstawowe dane
Zaletą Core Data jest odwrotne relacje. Więc jeśli chcesz po prostu nadać obiektowi NotesViewController obiekt notatek, możesz to zrobić, ponieważ będzie on miał odwrotny związek z czymś innym, jak zeszyt. Jeśli potrzebujesz danych na notatniku w programie NotesViewController, możesz wrócić do wykresu obiektowego, wykonując następujące czynności:
Przeczytaj więcej na ten temat w moim blogu: Udostępnianie kodu modelu
źródło
NewsViewController
NewsDetailViewController.h
NewsDetailViewController.m
źródło
Delegowanie to jedyne rozwiązanie, które wykonuje takie operacje, gdy używasz plików .xib, jednak wszystkie opisane powyżej odpowiedzi
storyboard
dotyczą plików .xib, których potrzebujesz do delegowania. to jedyne rozwiązanie, jakie możesz.Innym rozwiązaniem jest jednorazowe zainicjowanie wzorca klasy singleton i użycie go w całej aplikacji.
źródło
jeśli chcesz przekazać dane z ViewControlerOne do ViewControllerTwo wypróbuj te ..
wykonaj to w ViewControlerOne.h
zrób to w ViewControllerTwo.h
Syntezuj str2 w ViewControllerTwo.m
wykonaj to w ViewControlerOne.m
na przyciskach kliknij zdarzenie, zrób to ..
wykonaj to w ViewControllerTwo.m
źródło
Możesz zapisać dane w aplikacji Delegat, aby uzyskać do nich dostęp na kontrolerach widoku w aplikacji. Wszystko, co musisz zrobić, to utworzyć udostępnioną instancję delegata aplikacji
Na przykład
jeśli zadeklarujesz
NSArray object *arrayXYZ
a, możesz uzyskać do niego dostęp w dowolnym kontrolerze widoku przezappDelegate.arrayXYZ
źródło
Jeśli chcesz wysłać dane z jednego do drugiego viewController, oto sposób na to:
Powiedzmy, że mamy viewControllers: ViewController i NewViewController.
w ViewController.h
w ViewController.m
W NewViewController.h
W NewViewController.m
W ten sposób możemy przekazać dane z jednego kontrolera widoku do innego kontrolera widoku ...
źródło
Podoba mi się pomysł modelowania obiektów i próbnych obiektów opartych na NSProxy do zatwierdzania lub odrzucania danych, jeśli to, co wybierze użytkownik, można anulować.
Łatwo jest przekazywać dane, ponieważ jest to pojedynczy obiekt lub kilka obiektów, a jeśli powiedzmy, że kontroler UINavigationController, możesz zachować odniesienie do modelu w środku, a wszystkie kontrolery widoku wypychanego mogą uzyskać do niego dostęp bezpośrednio z kontrolera nawigacji.
źródło
Widziałem wielu ludzi, którzy komplikują to przy użyciu tej
didSelectRowAtPath
metody. Korzystam z podstawowych danych w moim przykładzie.4 linie kodu w metodzie i gotowe.
źródło
Istnieje wiele odpowiedzi na te pytania, oferujących wiele różnych sposobów wykonywania komunikacji z kontrolerem widoku, które rzeczywiście działałyby, ale nigdzie nie wspomniano, które z nich najlepiej użyć, a które należy unikać.
W praktyce moim zdaniem zalecane jest tylko kilka rozwiązań:
prepare(for:sender:)
metodęUIViewController
korzystania z storyboardu i seguRozwiązania, których NIE zalecam używać:
Rozwiązania te, choć działają krótkoterminowo, wprowadzają zbyt wiele zależności, które zniekształcają architekturę aplikacji i powodują więcej problemów później.
Dla zainteresowanych napisałem kilka artykułów, które bardziej szczegółowo omawiają te kwestie i podkreślają różne wady:
źródło