Запобігати появі розладів у методі PrepaForSegue?


249

Чи можливо скасувати розтин в prepareForSegue:методі?

Я хочу здійснити деяку перевірку перед segue, і якщо умова не відповідає дійсності (в цьому випадку, якщо якась UITextFieldпорожня), відобразити повідомлення про помилку замість виконання Segue.

Відповіді:


485

Це можливо в iOS 6 і пізніших версіях. Ви повинні реалізувати метод

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

На ваш погляд контролер. Ви робите там перевірку, і якщо це нормально, тоді, return YES;якщо її немає, тоді return NO;і підготовкаForSegue не викликається.

Зауважте, що цей метод не викликається автоматично при запуску програмних програм. Якщо вам потрібно здійснити перевірку, вам доведеться зателефонувати в callPerformSegueWithIdentifier, щоб визначити, чи слід виконувати segue.


106
FYI, якщо segue запускається програмно за допомогою виклику [self performSegueWithIdentifier: @ "segueIdentifier" відправника: nil]; shouldPerformSegueWithIdentifier ніколи не дзвонить.
Чувак

3
@Thedude дякую, що вказали на це. Відстежував проблему, і це не вдарило про мій перелом. Для тих, хто цікавиться, вам просто потрібно зателефонувати цьому методу, загорнутому в оператор if, щоб отримати той самий результат.
jpittman

1
@jpittman, будь ласка, поясніть, що ви маєте на увазі в заяві if?
Бода Тальйо

7
@AubadaTaljo: (вибачення за форматування) if ([self shouldPerformSegueWithIdentifier:@"segueIdentifier" sender:nil]) { [self performSegueWithIdentifier:@"segueIdentifier" sender:nil]; }
TimMedcalf

Спробував це в iOS 11.3 SDK з розвідки розкадрівки, і "mustPerformSegueWithIdentifier" подзвонили автоматично
Menno

52

Примітка: прийнята відповідь є найкращим підходом, якщо ви можете націлити на iOS 6. Для націлювання на iOS 5 ця відповідь буде дійсною.

Я не вірю, що можна скасувати сегмент в prepareForSegue. Я б запропонував перенести вашу логіку до того, що performSegueповідомлення вперше буде надіслане.

Якщо ви використовуєте програму Interface Builder для підключення каналу безпосередньо до елемента керування (наприклад, зв’язування каналу безпосередньо з a UIButton), ви можете досягти цього за допомогою трохи рефакторингу. Підключіть segue до контролера перегляду замість конкретного елемента управління (видаліть старе посилання, а потім перетягніть його з самого контролера подання на контролер подання призначення). Потім створіть IBActionу вашому контролері подання та підключіть елемент керування до IBAction. Тоді ви можете виконати свою логіку (перевірити наявність порожнього TextField) у створеному вами IBAction і вирішити, чи потрібно це performSegueWithIdentifierпрограмно.


Якщо segue спрямований до контролера, що потребує переходу, вам не потрібно повторно натискати кнопку, щоб створити інший контролер потужності; правильне, що потрібно зробити в цьому випадку, - це звільнити попу. Ваша відповідь передбачає таку правильну поведінку. Якщо ви підключите його прямо з кнопки на аркуші розкладу, я все одно не бачу правильної поведінки.
wcochran

1
Після кількох розчарувальних годин спроб змусити декілька споживачів, що базуються на сегсі, щоб грати добре разом, я здався і позбувся бідних секвенцій на користь цього рішення. Насправді використовується менше коду.
mpemburn

Хіба це поразка не була б метою отримання сегсів?
Крістік

Факт пов’язання ViewController з ViewController вирішив мою проблему. Дякую! Це найкраще рішення
д-р TJ

19

Swift 3 : func shouldPerformSegue (з ідентифікатором ідентифікатора: String, відправник: Будь-який?) -> Bool

Повернене значення відповідає дійсності, якщо слід проводити Segue або помилково, якщо його слід ігнорувати.

Приклад :

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

Крім того, дещо погана поведінка - запропонувати кнопку, яку користувач не повинен натискати. Ви можете залишити провідний канал як підставки, але почніть з відключеної кнопки. Потім підключіть "editingChanged" UITextField до події на алі управління перегляду

- (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
Так? Чи можете ви детальніше розглянути цю відповідь? Відповіді, кодові лише для коду, не дуже корисні для подальших читачів ...
Крістік

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];справді правдива?
Бен Уілер

@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

Аналогічна відповідь Каоліна полягає в тому, щоб залишити послідовність, пов'язану з контролем, але перевірити контроль за умовами, які є в огляді. Якщо ви запускаєте взаємодію стільникової таблиці, вам також потрібно встановити властивість 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 і повернути нуль, якщо ви не хочете показувати segue. showDetails()- це якийсь бул. У більшості випадків слід реалізувати в моделі даних, яка представлена ​​в комірці з indexPath.

 func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
        if showDetails() {
                return indexPath            
        }
        return nil
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.