Функция Mutating в расширении протокола, где Self - UIViewController
Я написал протокол и соответствующее расширение, которое использует простое StringStack
в тандеме с соглашением об именах в форме "<origin>@<destination>"
выполнять переходы между вложенными представлениями в моем приложении Swift. Я новичок в swift, так что если есть лучший способ реализовать то, что по сути является кнопками "вперед" и "назад" в нескольких представлениях, я открыт для этого. Однако следующий код проблематичен по причинам, которые я подробно опишу ниже.
struct StringStack {
var stack: Array = [String]()
mutating func push(str: String)->Void {
self.stack.append(str)
}
mutating func pop()->String {
self.stack.popLast()
}
}
protocol SegueForwardAndBackward {
var thisIdentifier: String {get set}
var segueStack: StringStack {get set}
}
extension SegueForwardAndBackward where Self: UIViewController {
mutating func performForwardSegue(nextIdentifier: String) {
let identifier: String = thisIdentifier + "@" + nextIdentifier
segueStack.push(identifier)
performSegueWithIdentifier(identifier, sender: self)
}
mutating func performBackwardSegue() {
let divided = segueStack.pop().componentsSeparatedByString("@")
// reverses destination and origin of identifier
let segueIdentifier: String = divided[1] + "@" + divided[0]
performSegueWithIdentifier(segueIdentifier, sender: self)
}
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if var destinationViewController: SegueForwardAndBackward = segue.destinationViewController as? SegueForwardAndBackward {
destinationViewController.segueStack = segueStack
}
}
}
Моя первоначальная проблема заключается в том, что функции расширения не допускаются в расширении протокола, как подробно описано в этом отчете об ошибках. В этом отчете предложен обходной путь, однако приведенные ниже ошибки приводят к тому, что 'SegueForwardAndBackward' is not a subtype of 'UIViewController'
,
class A: UIViewController, SegueForwardAndBackward {
mutating func testFunc() {
var p: SegueForwardAndBackward = self
p.performBackwardSegue()
}
}
Я наткнулся на потенциальное решение, где я мог бы сделать SegueForwardAndBackward
протокол класса, как подробно описано в другом вопросе. Однако реализация протокола класса приводит к segfault, который я предполагаю, потому что я объявляю свое расширение where Self: UIViewController
и, к сожалению, я понятия не имею, как решить эту проблему.
На данный момент я весьма разочарован тем, что кажется еще одной ошибкой в Swift, поэтому любая помощь в переработке моего подхода или расшифровке этих ошибок будет высоко ценится.
Заранее спасибо за ваш ответ!
2 ответа
Похоже, что этот вопрос касается альтернативного решения для вложенных кнопок "вперед" и "назад", поэтому без каких-либо других ответов это то, с чем я буду работать. Однако проблема, которую я поставил, все еще выделяется как довольно странная ошибка в swift.
Погрузившись немного глубже, я обнаружил, что модификатор мутации для функций в расширениях протокола в вашем случае не нужен, если вы добавите немутацию в segueStack. Потому что ты говоришь
struct StringStack {
var stack: Array = [String]()
mutating func push(str: String)->Void {
self.stack.append(str)
}
mutating func pop()->String? {
self.stack.popLast()
}
}
protocol SegueForwardAndBackward {
var thisIdentifier: String {get set}
var segueStack: StringStack {get nonmutating set}
}
extension SegueForwardAndBackward where Self: UIViewController {
func performForwardSegue(nextIdentifier: String) {
let identifier: String = thisIdentifier + "@" + nextIdentifier
segueStack.push(str: identifier)
performSegue(withIdentifier: identifier, sender: self)
}
func performBackwardSegue() {
guard let divided = segueStack.pop()?.components(separatedBy: "@") else { return }
// reverses destination and origin of identifier
let segueIdentifier: String = divided[1] + "@" + divided[0]
performSegue(withIdentifier: segueIdentifier, sender: self)
}
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if var destinationViewController: SegueForwardAndBackward = segue.destination as? SegueForwardAndBackward {
destinationViewController.segueStack = segueStack
}
}
}
И ваш класс будет выглядеть
class A: UIViewController, SegueForwardAndBackward {
var thisIdentifier: String
var segueStack: StringStack
func testFunc() {
self.performBackwardSegue
}
init(thisIdentifier: String, segueStack: StringStack) {
super.init(nibName: "A", bundle: .main)
self.thisIdentifier = thisIdentifier
self.segueStack = segueStack
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Однако это означает, что если вы согласуете структуру с SegueForwardAndBackward, вам потребуется реализовать неизменяемый набор.
struct B: SegueForwardAndBackward {
var thisIdentifier: String
var segueStack: StringStack { //Toy example
get {
UserDefaults.standard.object(forKey: "someKey") as! StringStack
}
nonmutating set {
UserDefaults.standard.set(newValue, forKey: "someKey")
}
}
}