ป้องกันการแยกในวิธีการเตรียมความพร้อมก่อนเริ่ม?


249

เป็นไปได้ไหมที่จะยกเลิกการทำต่อในprepareForSegue:วิธีการ?

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

คำตอบ:


485

เป็นไปได้ใน iOS 6 และใหม่กว่า: คุณต้องใช้วิธีนี้

- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender 

ในตัวควบคุมมุมมองของคุณ คุณทำการตรวจสอบของคุณที่นั่นและถ้ามันก็โอเคreturn YES;ถ้ามันไม่เป็นเช่นนั้นreturn NO;และไม่ได้มีชื่อว่า

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


106
FYI หากมีการเรียกใช้งาน Segue แบบเป็นโปรแกรมโดยการเรียก [self performSegueWithIdentifier: @ "segueIdentifier" ผู้ส่ง: ไม่มี]; shouldPerformSegueWithIdentifier จะไม่ถูกเรียก
เพื่อน

3
@ ขอบคุณสำหรับการชี้ออก กำลังติดตามปัญหาและมันไม่ได้กระทบกับเบรกพอยต์ของฉัน สำหรับใครที่อยากรู้อยากเห็นคุณต้องโทรหาวิธีนี้ในคำสั่ง if เพื่อให้ได้ผลลัพธ์เดียวกัน
jpittman

1
@jpittman คุณจะช่วยอธิบายสิ่งที่คุณหมายถึงห่อในคำสั่ง if?
Boda Taljo

7
@AubadaTaljo: (ขออภัยในการจัดรูปแบบ) if ([self shouldPerformSegueWithIdentifier:@"segueIdentifier" sender:nil]) { [self performSegueWithIdentifier:@"segueIdentifier" sender:nil]; }
TimMedcalf

พยายามทำสิ่งนี้ใน iOS 11.3 SDK จากกระดานเรื่องราวและ "shouldPerformSegueWithIdentifier" ถูกเรียกโดยอัตโนมัติ
Menno

52

หมายเหตุ: คำตอบที่ยอมรับเป็นวิธีที่ดีที่สุดหากคุณสามารถกำหนดเป้าหมาย iOS 6 สำหรับการกำหนดเป้าหมาย iOS 5 คำตอบนี้จะทำ

prepareForSegueผมไม่เชื่อว่ามันเป็นไปได้ที่จะยกเลิกการทำต่อใน ฉันขอแนะนำให้ย้ายตรรกะของคุณไปยังจุดที่performSegueข้อความถูกส่งครั้งแรก

หากคุณใช้ตัวสร้างส่วนต่อประสานสายย่อยโดยตรงกับตัวควบคุม (เช่นการเชื่อมต่อส่วนต่อโดยตรงกับ a UIButton) จากนั้นคุณสามารถทำสิ่งนี้ได้ด้วยการปรับเปลี่ยนเล็กน้อย วางสายต่อไปยังตัวควบคุมมุมมองแทนตัวควบคุมที่เฉพาะเจาะจง (ลบลิงก์ตัวต่อที่เก่าแล้วลากตัวควบคุมจากตัวควบคุมมุมมองไปยังตัวควบคุมมุมมองปลายทาง) จากนั้นสร้างIBActionตัวควบคุมในมุมมองของคุณและเชื่อมโยงตัวควบคุมไปยัง IBAction จากนั้นคุณสามารถทำตรรกะของคุณ (ตรวจสอบฟิลด์ข้อความว่าง) ใน IBAction ที่คุณเพิ่งสร้างขึ้นและตัดสินใจว่าจะเขียนperformSegueWithIdentifierโปรแกรมหรือไม่


ถ้า segue เป็นตัวควบคุม popover คุณไม่ต้องการให้แตะปุ่มที่สองเพื่อสร้างตัวควบคุม popover ตัวอื่น สิ่งที่ถูกต้องที่จะทำในกรณีนี้คือการปิดกั้น popover คำตอบของคุณอนุญาตสำหรับพฤติกรรมที่เหมาะสมนี้ หากคุณโยงมันโดยตรงจากปุ่มในกระดานเรื่องราวฉันไม่เห็นอยู่ดีว่าจะมีพฤติกรรมที่เหมาะสม
wcochran

1
หลังจากหลายชั่วโมงที่น่าหงุดหงิดที่พยายามให้ป๊อปอัปที่อิงกับเซกีหลาย ๆ ตัวเล่นกันฉันก็ยอมแพ้และกำจัดลำดับป๊อปโอเวอร์เพื่อสนับสนุนโซลูชันนี้ มันใช้รหัสน้อยลง
mpemburn

สิ่งนี้จะไม่ทำลายจุดประสงค์ของการมีหรือไม่?
Cristik

ข้อเท็จจริงที่จะเชื่อมโยง ViewController กับ ViewController แก้ไขปัญหาของฉัน ขอบคุณ! นี่เป็นทางออกที่ดีที่สุด
Dr TJ

19

Swift 3 : func shouldPerformSegue (withIdentifier identifier: String, sender: Any?) -> Bool

ค่าส่งคืนจริงถ้าควรดำเนินการหรือเท็จถ้ามันควรจะถูกละเว้น

ตัวอย่าง :

var badParameters:Bool = true

override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
    if badParameters  {
         // your code here, like badParameters  = false, e.t.c
         return false
    }
    return true
}

12

อีกวิธีหนึ่งคือมันเป็นพฤติกรรมที่ไม่ดีที่จะให้ปุ่มที่ผู้ใช้ไม่ควรกด คุณสามารถปล่อยให้สายสัญญาณตามที่ยืน แต่เริ่มต้นด้วยปุ่มปิดใช้งาน จากนั้นต่อสาย "editChanged" ของ UITextField เข้ากับเหตุการณ์บน ala control view

- (IBAction)nameChanged:(id)sender {
    UITextField *text = (UITextField*)sender;
    [nextButton setEnabled:(text.text.length != 0)];
}

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

11

มันง่ายในรวดเร็ว

override func shouldPerformSegueWithIdentifier(identifier: String,sender: AnyObject?) -> Bool {

    return true
}

3
ฮะ? คุณช่วยอธิบายเพิ่มเติมเกี่ยวกับคำตอบนี้ได้ไหม? คำตอบที่ใช้เฉพาะโค้ดไม่ได้มีประโยชน์มากสำหรับผู้อ่านต่อ ...
Cristik

9

ดังที่อับราฮัมกล่าวไว้ตรวจสอบความถูกต้องหรือไม่ในหน้าที่ต่อไปนี้

- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(nullable id)sender
{
     // Check this identifier is OK or NOT.
}

และการperformSegueWithIdentifier:sender:เรียกโดยการเขียนโปรแกรมสามารถบล็อกได้โดยการเขียนทับวิธีต่อไปนี้ โดยค่าเริ่มต้นจะไม่ตรวจสอบความถูกต้องหรือไม่โดย-shouldPerformSegueWithIdentifier:sender:เราสามารถทำได้ด้วยตนเอง

- (void)performSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{
    // Check valid by codes
    if ([self shouldPerformSegueWithIdentifier:identifier sender:sender] == NO) {
        return;
    }

    // If this identifier is OK, call `super` method for `-prepareForSegue:sender:` 
    [super performSegueWithIdentifier:identifier sender:sender];
}

ส่วนนี้เกี่ยวกับ[super performSegueWithIdentifier:identifier sender:sender];ความจริงจริงเหรอ?
Ben Wheeler

@BenWheeler คุณสามารถลอง หากคุณแทนที่performSegueWithIdentifier:sender:วิธีการและไม่เรียกว่าเป็นsuperวิธีการ
AechoLiu

5

ควรทำ Segue สำหรับการลงทะเบียนเข้าสู่ระบบ

-(BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{

    [self getDetails];

    if ([identifier isEqualToString:@"loginSegue"])
    {

        if (([_userNameTxtf.text isEqualToString:_uname])&&([_passWordTxtf.text isEqualToString:_upass]))
        {

            _userNameTxtf.text=@"";
            _passWordTxtf.text=@"";

            return YES;
        }
        else
        {
            UIAlertView *loginAlert = [[UIAlertView alloc] initWithTitle:@"Alert" message:@"Invalid Details" delegate:self cancelButtonTitle:@"Try Again" otherButtonTitles:nil];

            [loginAlert show];

            _userNameTxtf.text=@"";
            _passWordTxtf.text=@"";

            return NO;
        }

    }

    return YES;

}

-(void)getDetails
{
    NSArray *dir=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

    NSString *dbpath=[NSString stringWithFormat:@"%@/userDb.sqlite",[dir lastObject]];

    sqlite3 *db;

    if(sqlite3_open([dbpath UTF8String],&db)!=SQLITE_OK)
    {
        NSLog(@"Fail to open datadbase.....");
        return;
    }

    NSString *query=[NSString stringWithFormat:@"select * from user where userName = \"%@\"",_userNameTxtf.text];

    const char *q=[query UTF8String];

    sqlite3_stmt *mystmt;

    sqlite3_prepare(db, q, -1, &mystmt, NULL);

    while (sqlite3_step(mystmt)==SQLITE_ROW)
    {
        _uname=[NSString stringWithFormat:@"%s",sqlite3_column_text(mystmt, 0)];

        _upass=[NSString stringWithFormat:@"%s",sqlite3_column_text(mystmt, 2)];
    }

    sqlite3_finalize(mystmt);
    sqlite3_close(db);

}

4

เช่นเดียวกับคำตอบของ Kaolin คือปล่อยให้ seque ต่อสายควบคุม แต่ตรวจสอบการควบคุมตามเงื่อนไขในมุมมอง หากคุณกำลังโต้ตอบกับเซลล์ของตารางคุณต้องตั้งค่าคุณสมบัติ userInteractionEnabled รวมถึงปิดใช้งานเนื้อหาในเซลล์

ตัวอย่างเช่นฉันมีแบบฟอร์มในมุมมองตารางที่จัดกลุ่ม หนึ่งในเซลล์นำไปสู่ ​​tableView อื่นที่ทำหน้าที่เป็นตัวเลือก เมื่อใดก็ตามที่มีการเปลี่ยนแปลงการควบคุมในมุมมองหลักฉันเรียกวิธีนี้

-(void)validateFilterPicker
{
    if (micSwitch.on)
    {
        filterPickerCell.textLabel.enabled = YES;
        filterPickerCell.detailTextLabel.enabled = YES;
        filterPickerCell.userInteractionEnabled = YES;
        filterPickerCell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    }
    else
    {
        filterPickerCell.textLabel.enabled = NO;
        filterPickerCell.detailTextLabel.enabled = NO;
        filterPickerCell.userInteractionEnabled = NO;
        filterPickerCell.accessoryType = UITableViewCellAccessoryNone;
    }

}

4

Swift 4 คำตอบ:

ต่อไปนี้คือการนำไปใช้ของ Swift 4 เพื่อยกเลิกการทำต่อ:

override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
    if identifier == "EditProfile" {
        if userNotLoggedIn {
            // Return false to cancel segue with identified Edit Profile
            return false
        }
    }
    return true
}

2

อีกวิธีหนึ่งคือการแทนที่เมธอดของ tableView ด้วย willSelectRowAt และคืนค่าศูนย์ถ้าคุณไม่ต้องการแสดงเซกเมนต์ showDetails()- เป็นคนโง่ indexPathในกรณีส่วนใหญ่ควรจะดำเนินการในรูปแบบข้อมูลเป็นตัวแทนในมือถือที่มี

 func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
        if showDetails() {
                return indexPath            
        }
        return nil
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.