Запутанные параметры перехода в Swift, возможно, устаревший способ написания вещей?

#ios #swift #xcode #segue

Вопрос:

Я читал, как кто-то писал метод performSegue в такой функции, как эта:

 func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
    guard let annotation = mapView.selectedAnnotations.first else {return}
    selectedRestaurant = annotation as? RestaurantItem
    self.performSegue(withIdentifier: Segue.showDetail.rawValue, sender: self)
}
 

Мой вопрос в том, что из других книг, которые я читал, включая руководство Apple по XCode 12, я бы подумал написать что-то подобное.

 performSegue(withIdentifier: showDetail, sender: nil)
 

Я не могу понять смысл/значение добавления self » до performSegue » и «после sender: «, поскольку они выглядят излишними.

Аналогично, я бы просто написал в showDetail качестве идентификатора Segue. Для чего Segue. .rawValue нужны » до » и «после showDetail «? Кажется, я не нахожу никого, кто бы учил людей писать таким образом.

Может быть, это какой-то устаревший способ написания сегментов, когда я читаю книги, написанные в 2020 и/или 2021 годах?

Спасибо…!

Комментарии:

1. Вы можете опустить self. это, если хотите. self. необходимо только внутри закрытия или когда у вас есть 2 переменные с одинаковым именем

2. sender: self это потому, что «Объект, который вы хотите использовать для инициирования перехода. Этот объект предоставляется в информационных целях во время фактического этапа.» Документация

3. «Этот объект предоставляется в информационных целях во время фактического перехода». < — по сути, звучит так, как будто он не нужен и может также использоваться sender: nil на практике???

Ответ №1:

sender Параметр является произвольным и задан по соображениям совместимости с prepare(for segue:sender:) методом.

В жестко запрограммированном сегменте sender это либо UITableViewCell то, либо UIViewController другое, в зависимости от соединения.

Внутрь performSegue(withIdentifier:sender вы можете пройти все, что захотите. Если вам не нужен sender пропуск nil , но вы можете даже пройти annotation его, чтобы избавиться от временного имущества.


Что касается идентификаторов, то типобезопасным и более сложным способом обработки идентификаторов является, например, протокол

 protocol SegueHandlerType {
    associatedtype SegueIdentifier : RawRepresentable
}
 

и расширение, которое перегружает performSegue(withIdentifier:sender: метод

 extension SegueHandlerType where Self : UIViewController, SegueIdentifier.RawValue == String {
    
    func performSegue(withIdentifier segueIdentifier : SegueIdentifier, sender: Any?) {
        performSegue(withIdentifier: segueIdentifier.rawValue, sender:sender)
    }
    
    func segueIdentifer(for segue : UIStoryboardSegue) -> SegueIdentifier {
        guard let identifier = segue.identifier, let segueIdentifier = SegueIdentifier(rawValue: identifier) else {
            fatalError("Invalid segue identifier (segue.identifier!)")
        }
        return segueIdentifier
    }
}
 

Преимущество заключается в том, что идентификаторы являются перечислениями, которые проверяются во время компиляции.

Затем вы можете принять протокол в контроллере представления и объявить

 enum SegueIdentifier : String {
    case pushDetail = "PushDetail"
}

...

performSegue(withIdentifier: .pushDetail, sender: annotation)
 

и внутри prepare(for segue вы можете проверить

 override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segueIdentifer(for: segue) == .pushDetail {
       let annotation = sender as! RestaurantItem
...