PreparForSegue yönteminde segue önlensin mi?


249

prepareForSegue:Yöntemde bir segue iptal edilebilir mi?

Segue'ten önce bazı kontroller yapmak istiyorum ve koşul doğru değilse (bu durumda, bazıları UITextFieldboşsa), segue yerine bir hata mesajı görüntüleyin.

Yanıtlar:


485

İOS 6 ve sonraki sürümlerde mümkündür: Yöntemi uygulamanız gerekir

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

Görünüm denetleyicinizde. Doğrulamanızı orada yaparsınız ve eğer sorun olmazsa o zaman return YES;değilse return NO;ve preparForSegue çağrılmaz.

Programlı olarak tetikleme yapılırken bu yöntemin otomatik olarak çağrılmadığını unutmayın. Kontrolü yapmanız gerekirse segue işlemi yapıp yapmayacağınızı belirlemek için shouldPerformSegueWithIdentifier öğesini çağırmanız gerekir.


106
FYI, segue [self performSegueWithIdentifier: @ "segueIdentifier" sender: nil] çağrılarak programlı olarak tetiklenirse; shouldPerformSegueWithIdentifier hiçbir zaman çağrılmaz.
ahbap

3
@Thedude bunu işaret ettiğiniz için teşekkürler. Bir sorunu takip ediyordum ve bu benim kırılma noktama çarpmıyordu. Merak eden herkes için, aynı sonucu elde etmek için bir if ifadesine sarılmış bu yöntemi çağırmanız yeterlidir.
jpittman

1
@jpittman if ifadesine ne demek istediğini açıklar mısınız?
Boda Taljo

7
@AubadaTaljo: (biçimlendirme için özür dilerim) if ([self shouldPerformSegueWithIdentifier:@"segueIdentifier" sender:nil]) { [self performSegueWithIdentifier:@"segueIdentifier" sender:nil]; }
TimMedcalf

Bir hikaye panosu segue ve "shouldPerformSegueWithIdentifier" iOS 11.3 SDK otomatik olarak denendi
Menno

52

Not: iOS 6'yı hedefleyebiliyorsanız, kabul edilen cevap en iyi yaklaşımdır. İOS 5'i hedeflemek için bu cevap yapılır.

Bir segue'in iptal edilmesinin mümkün olduğuna inanmıyorum prepareForSegue. Mantığınızı performSeguemesajın ilk gönderildiği noktaya taşımanızı öneririm .

Arabirimi doğrudan bir kontrole bağlamak için Interface Builder kullanıyorsanız (örneğin, bir segue'i doğrudan a'ya bağlama UIButton), bunu biraz yeniden düzenleme ile yapabilirsiniz. Segue'i belirli bir kontrol yerine görünüm denetleyicisine bağlayın (eski segue bağlantısını silin ve ardından görünüm denetleyicisinin kendisinden hedef görünüm denetleyicisine kontrol sürükleyin). Ardından IBActiongörünüm denetleyicinizde bir oluşturun ve denetimi IBAction'a bağlayın. Daha sonra az önce oluşturduğunuz IBAction'da mantığınızı (boş TextField için kontrol edin) yapabilir ve orada performSegueWithIdentifierprogramlı olup olmayacağınıza karar verebilirsiniz .


Segue popover kontrolöre ise, do not başka popover denetleyicisi oluşturmak için düğmeye ikinci musluğu istiyorum; bu durumda yapılacak doğru şey, popover'ı kapatmaktır. Cevabınız bu uygun davranışa izin verir. Doğrudan film şeridindeki düğmeden bağlarsanız, doğru davranışı elde etmek için yine de görmüyorum.
wcochran

1
Birlikte güzelce oynamak için birden fazla segue tabanlı popover almaya çalışırken birkaç sinir bozucu saatten sonra, bu çözüm lehine popover sekmelerinden kurtuldum. Aslında daha az kod kullanır.
mpemburn

Bu segue olma amacını bozmaz mıydı?
Cristik

ViewController'ı ViewController'a bağlamak benim sorunumu çözdü. Teşekkür ederim! Bu en iyi çözüm
Dr TJ

19

Swift 3 : func shouldPerformSegue (withIdentifier tanımlayıcısı: String, gönderen: Herhangi biri?) -> Bool

Dönüş değeri true segue gerçekleştirilen veya gerekip gerekmediğini sahte göz ardı edilmelidir eğer.

Örnek :

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

Alternatif olarak, kullanıcının basmaması gereken bir düğme sunmak biraz kötü bir davranış. Segue'i stand olarak kablolu halde bırakabilirsiniz, ancak düğme devre dışı bırakılarak başlayın. Ardından, UITextField öğesinin "editingChanged" ifadesini görünüm denetimi ala'daki bir olaya bağlayın

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

"Alternatif olarak, kullanıcının basmaması gereken bir düğme sunmak biraz kötü bir davranış". Buna katılmıyorum - bu kısmen doğrudur ama gerçekten bağlama bağlıdır. Kullanıcıya rehberlik etmemek de kötü bir davranıştır - örneğin bir düğmeye dokunabilirler ve sistem önce ne yapılması gerektiğini açıklar. Devre dışı veya görünmez bir düğme ile kullanıcılar kaybolur veya destek çağırır ...
csmith

11

Hızlı kolay.

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

    return true
}

3
Ha? Bu cevap hakkında daha fazla ayrıntı verebilir misiniz? Yalnızca kod yanıtları diğer okuyucular için çok yararlı değildir ...
Cristik

9

İbrahim'in dediği gibi, aşağıdaki işlevde geçerli olup olmadığını kontrol edin.

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

Ve performSegueWithIdentifier:sender:programlama tarafından çağrılan aşağıdaki yöntem üzerine yazarak engellenebilir. Varsayılan olarak, geçerli olup olmadığını kontrol etmiyor -shouldPerformSegueWithIdentifier:sender:, manuel olarak yapabiliriz.

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

bu kısım [super performSegueWithIdentifier:identifier sender:sender];gerçekten doğru mu?
Ben Wheeler

@BenWheeler Deneyebilirsiniz. performSegueWithIdentifier:sender:Yöntemi geçersiz kılar ve yöntemini çağırmazsanız super.
AechoLiu

5

Giriş Kaydı için Segue Yapmalı

-(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'in cevabına benzer şekilde, sekmeyi kontrolüne bağlı bırakmak, ancak görünümü koşullara göre kontrolü doğrulamaktır. Tablo hücre etkileşimi üzerinde ateşliyorsanız, aynı zamanda userInteractionEnabled özelliğini ayarlamanız ve hücredeki öğeleri devre dışı bırakmanız gerekir.

Örneğin, gruplandırılmış bir tablo görünümünde bir form var. Hücrelerden biri, seçici görevi gören başka bir tableView öğesine yol açar. Ana görünümde bir kontrol değiştirildiğinde, bu yöntemi çağırırım

-(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 Cevap:

Segue iptal etmek için Swift 4 uygulaması aşağıdadır:

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

Diğer yol, willSelectRowAt ile tableView yöntemini geçersiz kılmak ve segue'i göstermek istemiyorsanız nil döndürmektir. showDetails()- biraz bool. Çoğu durumda hücrede temsil edilen veri modelinde uygulanmalıdır indexPath.

 func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
        if showDetails() {
                return indexPath            
        }
        return nil
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.