Cegah segue dalam metode prepForSegue?

249

Apakah mungkin untuk membatalkan segue dalam prepareForSegue:metode ini?

Saya ingin melakukan beberapa pemeriksaan sebelum segue, dan jika kondisinya tidak benar (dalam hal ini, jika beberapa UITextFieldkosong), tampilkan pesan kesalahan alih-alih melakukan segue.

Shmidt
sumber

Jawaban:

485

Itu dimungkinkan di iOS 6 dan yang lebih baru: Anda harus menerapkan metode ini

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

Di controller tampilan Anda. Anda melakukan validasi di sana, dan jika OK maka return YES;jika tidak maka return NO;dan prepForSegue tidak dipanggil.

Perhatikan bahwa metode ini tidak dipanggil secara otomatis ketika memicu segues secara terprogram. Jika Anda perlu melakukan pemeriksaan, maka Anda harus memanggil shouldPerformSegueWithIdentifier untuk menentukan apakah akan melakukan segue.

Abraham
sumber
106
FYI, jika segue dipicu secara pemrograman dengan memanggil [self performSegueWithIdentifier: @ "segueIdentifier" sender: nil]; shouldPerformSegueWithIdentifier tidak akan pernah dipanggil.
The dude
3
@Thedude terima kasih telah menunjukkan ini. Melacak masalah dan itu tidak mengenai breakpoint saya. Bagi siapa pun yang penasaran, Anda hanya perlu memanggil metode ini dengan pernyataan if untuk mendapatkan hasil yang sama.
jpittman
1
@jpittman tolong jelaskan apa maksudmu dengan pernyataan if?
Boda Taljo
7
@AubadaTaljo: (permintaan maaf untuk pemformatan) if ([self shouldPerformSegueWithIdentifier:@"segueIdentifier" sender:nil]) { [self performSegueWithIdentifier:@"segueIdentifier" sender:nil]; }
TimMedcalf
Mencoba ini di iOS 11.3 SDK dari segue storyboard dan "shouldPerformSegueWithIdentifier" memang dipanggil secara otomatis
Menno
52

Catatan: jawaban yang diterima adalah pendekatan terbaik jika Anda dapat menargetkan iOS 6. Untuk menargetkan iOS 5, jawaban ini akan berlaku.

Saya tidak percaya mungkin untuk membatalkan segue di prepareForSegue. Saya akan menyarankan untuk memindahkan logika Anda ke titik bahwa performSeguepesan pertama kali dikirim.

Jika Anda menggunakan Interface Builder untuk memasang segue langsung ke kontrol (mis. Menghubungkan segue langsung ke a UIButton), maka Anda dapat melakukannya dengan sedikit refactoring. Kawat segue ke pengontrol tampilan alih-alih kontrol tertentu (hapus tautan segue lama, lalu seret-kontrol dari pengontrol tampilan itu sendiri ke pengontrol tampilan tujuan). Kemudian buat IBActiondi controller tampilan Anda, dan kirim kontrol ke IBAction. Kemudian Anda dapat melakukan logika Anda (periksa TextField kosong) di IBAction yang baru saja Anda buat, dan putuskan di sana untuk performSegueWithIdentifierdiprogram atau tidak .

Mike Mertsock
sumber
Jika segue adalah untuk pengontrol popover, Anda tidak ingin ketukan kedua tombol untuk membuat pengontrol popover lainnya; hal yang benar untuk dilakukan dalam kasus ini adalah mengabaikan popover. Jawaban Anda memungkinkan untuk perilaku yang tepat ini. Jika Anda mengirimkannya langsung dari tombol di storyboard, saya tidak melihat pula untuk mendapatkan perilaku yang tepat.
wcochran
1
Setelah beberapa jam frustasi mencoba membuat beberapa popover berbasis segue untuk bermain bersama dengan baik, saya menyerah dan menyingkirkan popover seque demi solusi ini. Sebenarnya menggunakan lebih sedikit kode.
mpemburn
Bukankah ini akan mengalahkan tujuan memiliki segues?
Cristik
Fakta untuk menautkan ViewController ke ViewController memecahkan masalah saya. Terima kasih! Ini adalah solusi terbaik
Dr TJ
19

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

Mengembalikan nilai true jika segue harus dilakukan atau salah jika harus diabaikan.

Contoh :

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
}
OrdoDei
sumber
12

Atau, perilaku yang agak buruk untuk menawarkan tombol yang tidak boleh ditekan pengguna. Anda dapat membiarkan kabel segue berdiri, tetapi mulai dengan tombol dinonaktifkan. Kemudian kirimkan "editingChanged" ke UITextField ke acara dengan kontrol tampilan ala

- (IBAction)nameChanged:(id)sender {
    UITextField *text = (UITextField*)sender;
    [nextButton setEnabled:(text.text.length != 0)];
}
Api Kaolin
sumber
"Atau, itu perilaku yang agak buruk untuk menawarkan tombol yang tidak boleh ditekan pengguna". Saya tidak setuju dengan ini - ini sebagian benar tetapi sangat tergantung pada konteks. Ini juga merupakan perilaku buruk untuk tidak memandu pengguna - misalnya sehingga mereka dapat mengetuk tombol dan sistem menjelaskan apa yang perlu dilakukan terlebih dahulu. Dengan tombol yang dinonaktifkan atau tidak terlihat, pengguna akan tersesat atau menghubungi dukungan ...
csmith
11

Mudah dalam gerakan cepat.

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

    return true
}
Zumry Mohamed
sumber
3
Hah? Bisakah Anda menguraikan lebih lanjut tentang jawaban ini? Jawaban khusus kode tidak terlalu berguna untuk pembaca lebih lanjut ...
Cristik
9

Seperti kata Abraham, periksa valid atau tidak dalam fungsi berikut.

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

Dan, yang performSegueWithIdentifier:sender:dipanggil oleh pemrograman dapat diblokir dengan menimpa metode berikut. Secara default, ini tidak memeriksa valid atau tidak oleh -shouldPerformSegueWithIdentifier:sender:, kita bisa melakukannya secara manual.

- (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];
}
AechoLiu
sumber
Apakah ini bagian tentang yang [super performSegueWithIdentifier:identifier sender:sender];benar?
Ben Wheeler
@ BenWheeler Anda bisa mencobanya. Jika Anda mengganti performSegueWithIdentifier:sender:metode, dan tidak memanggil supermetode itu.
AechoLiu
5

Harus Melakukan Segue untuk Masuk Daftar

-(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);

}
Swappyee
sumber
4

Mirip dengan jawaban Kaolin adalah membiarkan kabel terhubung ke kontrol tetapi memvalidasi kontrol berdasarkan kondisi dalam tampilan. Jika Anda mengaktifkan interaksi sel tabel maka Anda juga perlu mengatur properti userInteractionEnabled serta menonaktifkan hal-hal di dalam sel.

Misalnya, saya punya formulir dalam tampilan tabel yang dikelompokkan. Salah satu sel mengarah ke tableView lain yang bertindak sebagai pemilih. Setiap kali kontrol diubah dalam tampilan utama saya memanggil metode ini

-(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;
    }

}
James Moore
sumber
4

Swift 4 Jawab:

Berikut ini adalah implementasi Swift 4 untuk membatalkan segue:

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
}
Pankaj Kulkarni
sumber
2

Cara lain adalah mengganti metode tableView dengan willSelectRowAt dan mengembalikan nil jika Anda tidak ingin menampilkan segue. showDetails()- Adalah beberapa bool. Dalam kebanyakan kasus harus diimplementasikan dalam model data yang diwakili dalam sel dengan indexPath.

 func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
        if showDetails() {
                return indexPath            
        }
        return nil
    }
Bogdan Ustyak
sumber