Подтвердить что ты не робот

Как проверить, может ли контроллер просмотра выполнить сеанс

Это может быть очень простой вопрос, но не дает никаких результатов при поиске, так что вот оно...

Я пытаюсь найти способ проверить, может ли определенный контроллер представления выполнить сеанс с идентификатором XYZ перед вызовом метода performSegueWithIdentifier:.

Что-то по строкам:

if ([self canPerformSegueWithIdentifier:@"SegueID"])
    [self performSegueWithIdentifier:@"SegueID"];

Возможные?

4b9b3361

Ответ 1

Как указано в документации:

Приложениям обычно не нужно запускать segues напрямую. Вместо этого вы настраиваете объект в Interface Builder, связанный с контроллер вида, такой как элемент управления, встроенный в свою иерархию представлений, для запуска segue. Однако вы можете вызвать этот метод, чтобы вызвать segue программно, возможно, в ответ на некоторые действия, которые не могут указывается в файле ресурсов раскадровки. Например, вы можете вызовите его из специального обработчика действий, используемого для обработки дрожания или события акселерометра.

Контроллер представления, который получает это сообщение, должен быть загружен из раскадровки. Если диспетчер представлений не имеет ассоциированного раскадровки, возможно, потому, что вы выделили и инициализировали ее самостоятельно, этот метод генерирует исключение.

При этом, когда вы запускаете segue, обычно это происходит потому, что предполагается, что UIViewController сможет ответить на него определенным идентификатором segue's. Я также согласен с Дэном F, вы должны попытаться избежать ситуаций, когда можно было бы исключить исключение. Поскольку вам не удастся сделать что-то вроде этого:

if ([self canPerformSegueWithIdentifier:@"SegueID"])
    [self performSegueWithIdentifier:@"SegueID"];

Я предполагаю, что:

  • respondsToSelector: проверяет, можете ли вы обрабатывать это сообщение во время выполнения. В этом случае вы можете, так как класс UIViewController способен отвечать на performSegueWithIdentifier:sender:. Чтобы действительно проверить, способен ли метод обрабатывать сообщение с определенными параметрами, я думаю, это было бы невозможно, потому что для того, чтобы определить, возможно ли это, нужно фактически запустить его, и при этом NSInvalidArgumentException будет расти.
  • Чтобы создать то, что вы предложили, было бы полезно получить список идентификаторов segue, с которыми связан UIViewController. Из UIViewController documentation я не смог найти ничего похожего на это

На данный момент я предполагаю, что лучше всего продолжать его с @try @catch @finally.

Ответ 2

Чтобы проверить, существовал ли segue или нет, я просто окружил вызов блоком try-and-catch. См. Пример кода ниже:

@try {
    [self performSegueWithIdentifier:[dictionary valueForKey:@"segue"] sender:self];
}
@catch (NSException *exception) {
    NSLog(@"Segue not found: %@", exception);
}

Надеюсь, что это поможет.

Ответ 3

- (BOOL)canPerformSegueWithIdentifier:(NSString *)identifier
{
    NSArray *segueTemplates = [self valueForKey:@"storyboardSegueTemplates"];
    NSArray *filteredArray = [segueTemplates filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"identifier = %@", identifier]];
    return filteredArray.count>0;
}

Ответ 4

Вот более правильный метод Swift для проверки существования segue:

extension UIViewController {
    func canPerformSegue(id: String) -> Bool {
        let segues = self.valueForKey("storyboardSegueTemplates") as? [NSObject]
        let filtered = segues?.filter({ $0.valueForKey("identifier") as? String == id })
        return (filtered?.count > 0) ?? false
    }

    // Just so you dont have to check all the time
    func performSegue(id: String, sender: AnyObject?) -> Bool {
        if canPerformSegue(id) {
            self.performSegueWithIdentifier(id, sender: sender)
            return true
        }
        return false
    }
}

// 1
if canPerformSegue("test") {
    self.performSegueWithIdentifier("test", sender: nil)
}

// 2
performSegue("test", sender: nil)

Ответ 5

Вы можете переопределить метод - (BOOL) shouldPerformSegueWithIdentifier: sender: method и сделать свою логику там.

- (BOOL) shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender {
    if ([identifier isEqualToString:@"someSegue"]) {
        if (!canIPerformSegue) {
            return NO;
        }
    }
    return YES;    
}

Надеюсь, что это поможет.

Ответ 6

Быстрая версия ответа Евгения Михайлова, который работал на меня:

Я повторно использую контроллер для двух видов. Это помогает мне повторно использовать код.

if(canPerformSegueWithIdentifier("segueFoo")) {
  self.performSegueWithIdentifier("segueFoo", sender: nil)
}
else {
  self.performSegueWithIdentifier("segueBar", sender: nil)
}


func canPerformSegueWithIdentifier(identifier: NSString) -> Bool {
    let templates:NSArray = self.valueForKey("storyboardSegueTemplates") as! NSArray
    let predicate:NSPredicate = NSPredicate(format: "identifier=%@", identifier)

    let filteredtemplates = templates.filteredArrayUsingPredicate(predicate)
    return (filteredtemplates.count>0)
}

Ответ 7

Невозможно проверить, что использование стандартных функций, что вы можете сделать, это подкласс UIStoryboardSegue и хранить информацию в контроллере представления source (который передается конструктору). В построителе интерфейса выберите "Custom" в качестве типа segue, как введите имя класса вашего segue, затем ваш конструктор будет вызываться для каждого созданного экземпляра, и вы можете запросить сохраненные данные, если он существует.

Вы также должны переопределить метод perform для вызова [source presentModalViewController:destination animated:YES] или [source pushViewController:destination animated:YES] в зависимости от того, какой тип перехода вы хотите.