วิธีผ่านการเตรียมตัวสำหรับส่วน: วัตถุ


357

ฉันมีคำอธิบายประกอบมากมายใน mapview (พร้อมrightCalloutAccessoryปุ่ม) ปุ่มนี้จะดำเนินการทำต่อจากนี้ไปmapview tableviewฉันต้องการส่งผ่านtableviewออบเจ็กต์อื่น (ที่เก็บข้อมูล) โดยขึ้นอยู่กับปุ่มไฮไลต์ที่ถูกคลิก

ตัวอย่างเช่น: (ทำขึ้นทั้งหมด)

  • คำอธิบายประกอบ 1 (ออสติน) -> pass data obj 1 (เกี่ยวข้องกับ Austin)
  • annotation2 (Dallas) -> pass data obj 2 (เกี่ยวข้องกับ Dallas)
  • คำอธิบายประกอบ 3 (Houston) -> ส่งผ่านข้อมูล obj 3 และอื่น ๆ ... (คุณได้รับแนวคิด)

ฉันสามารถตรวจพบว่ามีการคลิกปุ่มไฮไลต์ใด

ฉันใช้prepareForSegue: ในการส่งผ่านข้อมูล obj ViewControllerไปยังปลายทาง เนื่องจากฉันไม่สามารถใช้การเรียกนี้รับอาร์กิวเมนต์พิเศษสำหรับข้อมูล obj ที่ฉันต้องการวิธีที่สวยงามในการทำเอฟเฟกต์เดียวกัน (data data obj) คืออะไร?

เคล็ดลับใด ๆ ที่จะได้รับการชื่นชม


การทำซ้ำตัวแปร Pass ที่
Paulw11

คำตอบ:


673

เพียงหยิบการอ้างอิงไปยังคอนโทรลเลอร์มุมมองเป้าหมายในprepareForSegue:วิธีการและส่งผ่านวัตถุใด ๆ ที่คุณต้องการ นี่คือตัวอย่าง ...

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Make sure your segue name in storyboard is the same as this line
    if ([[segue identifier] isEqualToString:@"YOUR_SEGUE_NAME_HERE"])
    {
        // Get reference to the destination view controller
        YourViewController *vc = [segue destinationViewController];

        // Pass any objects to the view controller here, like...
        [vc setMyObjectHere:object];
    }
}

การแก้ไข: คุณยังสามารถใช้ performSegueWithIdentifier:sender:วิธีการเปิดใช้งานการเปลี่ยนเป็นมุมมองใหม่ตามการเลือกหรือกดปุ่ม

ตัวอย่างเช่นลองพิจารณาฉันมีตัวควบคุมมุมมองสองตัว ปุ่มแรกประกอบด้วยปุ่มสามปุ่มและปุ่มที่สองจำเป็นต้องรู้ว่าปุ่มใดถูกกดก่อนการเปลี่ยนภาพ คุณสามารถวางสายปุ่มลงIBActionในรหัสของคุณซึ่งใช้performSegueWithIdentifier:วิธีการเช่นนี้ ...

// When any of my buttons are pressed, push the next view
- (IBAction)buttonPressed:(id)sender
{
    [self performSegueWithIdentifier:@"MySegue" sender:sender];
}

// This will get called too before the view appears
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"MySegue"]) {

        // Get destination view
        SecondView *vc = [segue destinationViewController];

        // Get button tag number (or do whatever you need to do here, based on your object
        NSInteger tagIndex = [(UIButton *)sender tag];

        // Pass the information to your destination view
        [vc setSelectedButton:tagIndex];
    }
}

แก้ไข: แอปพลิเคชันตัวอย่างที่ฉันแนบมาตอนนี้อายุหกขวบดังนั้นฉันจึงลบมันเพื่อหลีกเลี่ยงความสับสน


ขอบคุณ แต่ฉันต้องการตั้งค่า[vc setMyObjectHere:object];แบบไดนามิกนี้ เช่น obj1 สำหรับ button1, obj2 สำหรับ button2 ปัญหาคือฉันไม่สามารถทะเลาะกันได้มีวิธีแก้ไขไหม?
chizzle

2
ฉันได้อัปเดตโพสต์ของฉันด้วยตัวอย่างที่ดาวน์โหลดได้ของสิ่งที่ฉันพูดถึง
Simon

ที่ได้ผล! ขอบคุณมัด เป็นการเตรียมพร้อมด้านหมายเหตุสำหรับ: มีอาร์กิวเมนต์ UIControl ซึ่งเป็นคลาสแม่ของ UIButton (สามารถรับแท็กได้): D
chizzle

PreparForSegue ได้รับการเรียกแม้ว่าคุณเพิ่งจะผลักดันไปยังตัวควบคุมการนำทางที่ไม่มีส่วนต่อกระดานเรื่องราวหรือไม่?
zakdances

นี่เป็นหนึ่งในคำตอบที่ละเอียดที่สุดที่ฉันเคยเห็น ตัวอย่างโค้ดที่ดีแก้ปัญหาเสนอตัวอย่างที่ดาวน์โหลดได้ ... ว้าว ฉันประทับใจ!
lewiguez

82

บางครั้งการหลีกเลี่ยงการสร้างการอ้างอิงเวลาคอมไพล์ระหว่างตัวควบคุมมุมมองสองตัว นี่คือวิธีที่คุณสามารถทำได้โดยไม่ต้องกังวลกับชนิดของตัวควบคุมมุมมองปลายทาง:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.destinationViewController respondsToSelector:@selector(setMyData:)]) {
        [segue.destinationViewController performSelector:@selector(setMyData:) 
                                              withObject:myData];
    } 
}

ดังนั้นตราบใดที่ตัวควบคุมมุมมองปลายทางของคุณประกาศคุณสมบัติสาธารณะเช่น:

@property (nonatomic, strong) MyData *myData;

คุณสามารถตั้งค่าคุณสมบัตินี้ในตัวควบคุมมุมมองก่อนหน้าตามที่อธิบายไว้ข้างต้น


12
นี่เป็นเรื่องของความคิดเห็น ฉันยังไม่ได้ (ยัง) มีสถานการณ์ที่ฉันไม่ต้องการควบคุมตัวควบคุมมุมมอง 'แน่น' แม้ว่าฉันจะขอบคุณสิ่งที่คุณพูดและมันอาจมีความสำคัญในสถานการณ์ที่เหมาะสม
Simon

2
@Simon: ใช่คุณเพียงแค่เลือกวิธีที่ดีที่สุดสำหรับคุณ ในแอพที่ฉันกำลังทำงานอยู่ตัวอย่างเช่นวิธีการของฉันมีเหตุผลอย่างมากเนื่องจากฉันยังคงเพิ่มตัวควบคุมมุมมองที่ต้องการวัตถุข้อมูลเดียวกัน ความสามารถในการเชื่อมต่อพวกเขาด้วยเพียงแค่ส่วนต่อขยายและรู้ว่าพวกเขาจะได้รับข้อมูลที่ถูกต้องนั้นสะดวกสบายเป็นพิเศษ
Macondo2Seattle

10
มันไม่ใช่เรื่องของความเห็นมันเป็นเรื่องผิด :) วลี "คำตอบที่ยอมรับไม่ใช่วิธีที่ดีที่สุดในการทำเช่นนี้" ผิด มันควรอ่าน "ในบางกรณีคุณจะต้องทำเช่นนี้ ..."
Fattie

2
ฉันชอบวิธีการของไซม่อน ตามที่จะบอกฉันข้อผิดพลาดในเวลารวบรวม ตัวอย่างเช่นหากฉันพลาดการประกาศ myData ในคอนโทรลเลอร์มุมมองปลายทางฉันจะรู้ได้ทันที แต่สำหรับสถานการณ์ของคุณแนวทางของคุณดูดี!
Abdurrahman Mubeen Ali

14
setMyData:วิธีการอย่างนี้จะสร้างการพึ่งพาในขณะที่คุณกำลังกำหนดตัวควบคุมมุมมองปลายทางที่จะมี นั่นคือการพึ่งพา ความจริงที่ว่าคุณใช้ตัวเลือกเพื่อหลีกเลี่ยงข้อผิดพลาดในการคอมไพล์ควรถือว่าเป็นจุดอ่อนของวิธีการของคุณไม่ใช่ผลประโยชน์ เป็นเรื่องที่น่าตกใจสำหรับฉันที่นักพัฒนาจำนวนมากสูญเสียแนวคิดที่ว่าข้อผิดพลาดในการคอมไพล์ควรเป็นที่ต้องการสำหรับข้อผิดพลาดรันไทม์
เนท

21

ใน Swift 4.2 ฉันจะทำสิ่งนี้:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let yourVC = segue.destination as? YourViewController {
        yourVC.yourData = self.someData
    }
}

คุณต้องโทรหา: `super.prepare (สำหรับ: ทำต่อ, ผู้ส่ง: ผู้ส่ง) '?
แอนดรู K

16

ฉันมีชั้นผู้ส่งเช่นนี้

@class MyEntry;

@interface MySenderEntry : NSObject
@property (strong, nonatomic) MyEntry *entry;
@end

@implementation MySenderEntry
@end

ฉันใช้คลาสผู้ส่งนี้สำหรับการส่งวัตถุไปprepareForSeque:sender:

-(void)didSelectItemAtIndexPath:(NSIndexPath*)indexPath
{
    MySenderEntry *sender = [MySenderEntry new];
    sender.entry = [_entries objectAtIndex:indexPath.row];
    [self performSegueWithIdentifier:SEGUE_IDENTIFIER_SHOW_ENTRY sender:sender];
}

-(void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:SEGUE_IDENTIFIER_SHOW_ENTRY]) {
        NSAssert([sender isKindOfClass:[MySenderEntry class]], @"MySenderEntry");
        MySenderEntry *senderEntry = (MySenderEntry*)sender;
        MyEntry *entry = senderEntry.entry;
        NSParameterAssert(entry);

        [segue destinationViewController].delegate = self;
        [segue destinationViewController].entry = entry;
        return;
    }

    if ([[segue identifier] isEqualToString:SEGUE_IDENTIFIER_HISTORY]) {
        // ...
        return;
    }

    if ([[segue identifier] isEqualToString:SEGUE_IDENTIFIER_FAVORITE]) {
        // ...
        return;
    }
}

เรากำลังใช้ prepareForSegueหรือเรากำลังใช้งานอยู่และข้อสันนิษฐานคือ PreparForSegue ได้รับการเรียกตัวเองเช่นเราไม่จำเป็นต้องทำอะไรเช่นนี้[self prepareForSegue]
ฮันนี่

15

ฉันเจอคำถามนี้เมื่อฉันพยายามที่จะเรียนรู้วิธีการส่งผ่านข้อมูลจาก View Controller หนึ่งไปยังอีก ฉันต้องการภาพเพื่อช่วยฉันเรียนรู้ดังนั้นคำตอบนี้เป็นส่วนเสริมของผู้อื่นที่นี่แล้ว มันค่อนข้างกว้างกว่าคำถามเดิมเล็กน้อย แต่สามารถปรับให้เข้ากับการทำงานได้

ตัวอย่างพื้นฐานนี้ทำงานดังนี้:

ป้อนคำอธิบายรูปภาพที่นี่

แนวคิดคือการส่งสตริงจากฟิลด์ข้อความในตัวควบคุมมุมมองที่หนึ่งไปยังป้ายชื่อในตัวควบคุมมุมมองที่สอง

ตัวควบคุมมุมมองแรก

import UIKit

class FirstViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!

    // This function is called before the segue
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

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

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

}

ตัวควบคุมมุมมองที่สอง

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
    }

}

จำไว้ว่าให้

  • สร้างส่วนย่อยโดยcontrolคลิกที่ปุ่มแล้วลากไปยังตัวควบคุมมุมมองที่สอง
  • ร้านเบ็ดขึ้นสำหรับและUITextFieldUILabel
  • ตั้งค่าตัวควบคุมมุมมองที่หนึ่งและที่สองเป็นไฟล์ Swift ที่เหมาะสมใน IB

แหล่ง

วิธีส่งข้อมูลผ่าน segue (swift) (บทช่วยสอนของ YouTube)

ดูสิ่งนี้ด้วย

ดูตัวควบคุม: การส่งต่อข้อมูลและส่งผ่านข้อมูลกลับ (คำตอบแบบเต็ม)


5

สำหรับSwiftใช้สิ่งนี้

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    var segueID = segue.identifier

    if(segueID! == "yourSegueName"){

        var yourVC:YourViewController = segue.destinationViewController as YourViewController

        yourVC.objectOnYourVC = setObjectValueHere!

    }
}

4

ฉันใช้ไลบรารีกับหมวดหมู่บน UIViewController ที่ทำให้การดำเนินการนี้ง่ายขึ้น โดยทั่วไปคุณตั้งค่าพารามิเตอร์ที่คุณต้องการส่งผ่านใน NSDictionary ที่เกี่ยวข้องกับรายการ UI ที่กำลังดำเนินการต่อ มันทำงานร่วมกับ segues ด้วยตนเองเช่นกัน

ตัวอย่างเช่นคุณสามารถทำได้

[self performSegueWithIdentifier:@"yourIdentifier" parameters:@{@"customParam1":customValue1, @"customValue2":customValue2}];

สำหรับการทำสำเนาด้วยตนเองหรือสร้างปุ่มที่มีการทำต่อและใช้งาน

[button setSegueParameters:@{@"customParam1":customValue1, @"customValue2":customValue2}];

หากคอนโทรลเลอร์มุมมองปลายทางไม่สอดคล้องกับการเข้ารหัสคีย์ - ค่าสำหรับคีย์จะไม่มีสิ่งใดเกิดขึ้น มันทำงานร่วมกับคีย์ - ค่าด้วยเช่นกัน (มีประโยชน์สำหรับการแบ่งเซกเมนต์) ลองใช้งานได้ที่นี่ https://github.com/stefanomondino/SMQuickSegue


2

โซลูชันของฉันคล้ายกัน

// In destination class: 
var AddressString:String = String()

// In segue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
   if (segue.identifier == "seguetobiddetailpagefromleadbidder")
    {
        let secondViewController = segue.destinationViewController as! BidDetailPage
        secondViewController.AddressString = pr.address as String
    }
}

1

เพียงใช้ฟังก์ชั่นนี้

 override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let index = CategorytableView.indexPathForSelectedRow
    let indexNumber = index?.row
    let VC = segue.destination as! DestinationViewController
   VC.value = self.data

}

0

ฉันใช้โซลูชันนี้เพื่อให้สามารถเรียกใช้ segue และการสื่อสารข้อมูลภายในฟังก์ชันเดียวกันได้:

private var segueCompletion : ((UIStoryboardSegue, Any?) -> Void)?

func performSegue(withIdentifier identifier: String, sender: Any?, completion: @escaping (UIStoryboardSegue, Any?) -> Void) {
    self.segueCompletion = completion;
    self.performSegue(withIdentifier: identifier, sender: sender);
    self.segueCompletion = nil
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    self.segueCompletion?(segue, sender)
}

กรณีการใช้งานจะเป็นสิ่งที่ต้องการ:

func showData(id : Int){
    someService.loadSomeData(id: id) {
        data in
        self.performSegue(withIdentifier: "showData", sender: self) {
            storyboard, sender in
            let dataView = storyboard.destination as! DataView
            dataView.data = data
        }
    }
}

ดูเหมือนว่าจะใช้งานได้สำหรับฉัน แต่ฉันไม่แน่ใจ 100% ว่าฟังก์ชั่นการดำเนินการและเตรียมการจะดำเนินการบนเธรดเดียวกันเสมอ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.