Sök…


Använda segrar (vidarebefordra data)

För att skicka data från den aktuella visningskontrollern till nästa nya visningskontrollerare (inte en tidigare visningskontrollerare) med hjälp av segment, skapar du först ett segment med en identifierare i relevant berättelse. Överstyr din nuvarande prepareForSegue metod prepareForSegue . Inuti metoden kontrollerar du det segment du just skapade med dess identifierare. Kasta destinationvisningsregulatorn och skicka data till den genom att ställa in egenskaper på nedkastningsvisningsstyrenheten.

Ställa in en identifierare för ett segment:

Tilldelar inspektör för ett segment

Segment kan utföras programmatiskt eller med knapphändelseshändelse som är inställd på storyboardet med ctrl + dra till destinationsvisningsstyrenheten. Du kan kräva ett segue programmatiskt, vid behov, med hjälp av segue-identifierare i visningskontrollern:

Objective-C

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

Snabb

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

Du kan konfigurera segue nyttolast i den åsidosatta versionen av metoden prepareForSegue . Du kan ställa in önskade egenskaper innan destinationsvisningsstyrenheten laddas.

Objective-C

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

Snabb

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

DetailViewController är namnet på den andra visningskontrollern och isDetailingEnabled är en offentlig variabel i den visningskontrollern.

För att utvidga detta mönster kan du behandla en offentlig metod på DetailViewController som en pseudoinitierare, för att hjälpa till att initialisera alla nödvändiga variabler. Detta kommer att själva dokumentera variabler som måste ställas in på DetailViewController utan att behöva läsa igenom dess källkod. Det är också ett praktiskt ställe att ställa in standardvärden.

Objective-C

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

Snabb

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

Använda delegatmönstret (vidarebefordra data)

För att skicka data från den aktuella visningskontrollern tillbaka till den föregående visningskontrollern kan du använda delegatmönstret.

ange bildbeskrivning här

Det här exemplet antar att du har skapat ett segue i Interface Builder och att du ställer in segmentidentifieraren till showSecondViewController . Outlets och handlingar måste också anslutas till namnen i följande kod.

First View Controller

Koden för First View Controller är

Snabb

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)
    }
}

Objective-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

Notera användningen av vårt anpassade DataEnteredDelegate protokoll.

Second View Controller and Protocol

Koden för den andra visningskontrollern är

Snabb

// 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 ?? "")
    }
}

Objective-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

Observera att protocol ligger utanför klassen View Controller.

Vidarebefordra data bakåt med hjälp av varva ner för att segue

I motsats till segment som låter dig överföra data "framåt" från den aktuella visningskontrollern till destinationsvisningsstyrenheten:

(VC1) -> (VC2)

Med hjälp av "varva ner" kan du göra det motsatta, skicka data från destinationen eller den aktuella visningskontrollern till dess nuvarande visningskontroller:

(VC1) <- (VC2)

OBS : Var uppmärksam på att med hjälp av avkylning kan du skicka data först och därefter kommer den aktuella visningskontrollern (VC2) att flyttas.

Så här gör du:

Först måste du lägga till följande deklaration vid den nuvarande visningskontrollern (VC1), som är den visningskontrollant som vi vill överföra data till:

@IBAction func unwindToPresentingViewController(segue:UIStoryboardSegue)

Det viktiga är att använda prefixet unwind , detta "informerar" Xcode om att detta är en avkopplingsmetod som ger dig möjlighet att använda det i storyboard också.

Efteråt måste du implementera metoden, den ser nästan ut som en verklig serie:

@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
        }

Nu har du två alternativ för att påkalla avlindningssamtal:

  1. Du kan "hård kod" åberopa: self.performSegueWithIdentifier("YourCustomIdentifier", sender: self) som kommer att varva ner åt dig när du performSegueWithIdentifier .
  2. Du kan länka avlastningsmetoden med hjälp av storyboard till ditt "Exit" -objekt: ctrl + dra knappen som du vill åberopa avlastningsmetoden, till "Exit" -objektet:

ange bildbeskrivning här

Släpp och du har möjlighet att välja din anpassade avkopplingsmetod:

ange bildbeskrivning här

Vidarebefordra data med hjälp av stängningar (vidarebefordra data)

Istället för att använda delegatmönstret , som delar implementeringen i olika delar av UIViewController klassen, kan du till och med använda closures att skicka data fram och tillbaka. Genom att anta att du använder UIStoryboardSegue , i metoden prepareForSegue du enkelt konfigurera den nya kontrollern i ett steg

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)
        }
    }
}

Detta är ett exempel på användning och det är bättre att använda på Swift, Objekt-C-blockets syntax är inte så lätt att göra koden mer läsbar

Med hjälp av återuppringning (blockering) vidarebefordran av data

detta ämne är en klassisk fråga i iOS-utveckling, och dess lösning är olika som andra exempel som redan visas. I det här exemplet ska jag visa en annan dag allmänt bruk ett: passerar data med hjälp av closure genom att anpassa delegate pattern exempel på denna sida i callback closure !

en sak den här metoden är överlägsen att delegate pattern är istället för att dela upp inställningskoden på två olika platser (se på delegatexempel på den här sidan, prepareForSegue , userDidEnterInformation ) snarare samla dem ihop (endast i prepareForSegue , jag ska visa det)

Börja från Second View Controller

vi måste ta reda på hur vi använder återuppringning, då kan vi skriva det, det är därför vi börjar från andra visningskontroller eftersom det är där vi använder återuppringning: när vi fick den nya textinmatningen, kallar vi återuppringningen och använder återuppringningsparametern som ett medium för att skicka data tillbaka till den första ViewController, lägg märke till att jag sa med hjälp av återuppringningsparameter, detta är mycket viktigt, nybörjare (som jag var) förbiser alltid detta och vet inte var jag ska börja skriva återuppringning korrekt

så i det här fallet vet vi att vår återuppringning bara tar en parameter: text och dess typ är String , låt oss förklara det och göra det till egenskap eftersom vi behöver fylla från vår första visningskontroller

Jag kommenterar bara alla delegate delar och håller den för att jämföra

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)
    }
}

Slutför den första visningskontrollern

allt du behöver göra är att passera återuppringning av stängning, och vi är klara, stängning kommer att göra det framtida arbetet för oss eftersom vi redan har konfigurerat det i andra visningskontrollen

se hur det gör vår kod kortare jämfört med 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
    //}
}

och i det sista, kanske någon av er förvirras av att vi bara skickar informationen (stängning i detta fall) bara på ett sätt, från första visningskontrollant till sekund, ingen direkt kommer tillbaka från andra visningskontrollant, hur kan vi betrakta det som ett kommunikationsverktyg? kanske du verkligen borde köra det och bevisa det själv, allt jag säger att det är parameter , det är återuppringningens parameter som skickar data tillbaka!

Genom att tilldela egendom (vidarebefordra data)

Du kan skicka data direkt genom att tilldela egenskapen till nästa visningskontroller innan du trycker på eller presenterar dem.

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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow