Я начинаю изучать Свифт и слежу за очень хорошими лекциями в Стэнфордском университете на YouTube. Вот ссылка, если вы заинтересованы или она помогает (хотя это не требуется для понимания моей проблемы):
Разработка приложений iOS 8 с Swift - 2. Больше Xcode и Swift, MVC
Когда я читал лекции, я дошел до точки, где (насколько я мог судить) мой код был идентичен коду в видео, но в моей системе я получил ошибку компилятора. После большого количества проб и ошибок я смог сократить свой код до двух примеров, один из которых генерирует ошибку, другой или нет, но я не знаю, что на самом деле вызывает ошибку или как ее разрешить.
Код, создающий ошибку:
import UIKit
class BugViewController: UIViewController
{
func perform(operation: (Double) -> Double) {
}
func perform(operation: (Double, Double) -> Double) {
}
}
Это создает следующую ошибку компилятора:
Метод "выполнить" с помощью Objective-C selector "выполнить:" конфликтует с предыдущим объявлением с тем же селектором Objective-C
Просто удалив подкласс UIViewController, компиляция кода:
import UIKit
class BugViewController
{
func perform(operation: (Double) -> Double) {
}
func perform(operation: (Double, Double) -> Double) {
}
}
Некоторая другая информация, которая может быть или не быть релевантной:
Я наполовину надеюсь, что это ошибка в компиляторе, потому что в противном случае это не имеет никакого смысла для меня. Любая помощь очень благодарна!
Objective-C не поддерживает перегрузку метода, вы должны использовать другое имя метода. Когда вы унаследовали UIViewController, вы унаследовали NSObject и сделали класс совместимым с Obj-C. С другой стороны, Swift поддерживает перегрузку, поэтому она работает, когда вы удаляете наследование.
UIFont
каждый день.
Я тоже принимаю курс Standford, и я тоже застрял здесь, но после некоторых поисков я нашел что-то отсюда: Примечания к выпуску Xcode и он упомянул что-то ниже:
Swift 1.2 строго придерживается проверки перегрузки на основе типа @objc методы и инициализаторы, что не поддерживается Objective-C.
// Has the Objective-C selector "performOperation:". func performOperation(op: NSOperation) { /* do something */ } // Also has the selector "performOperation:". func performOperation(fn: () -> Void) { self.performOperation(NSBlockOperation(block: fn)) }
Этот код будет работать при вызове из Swift, но может легко сработать если вызывается из Objective-C. Чтобы решить эту проблему, используйте тип, который не поддерживается Objective-C, чтобы предотвратить компилятор Swift от выставляя элемент в среду выполнения Objective-C:
- Если это имеет смысл, отметьте член как закрытый, чтобы отключить вывод @objc.
- В противном случае используйте фиктивный параметр со значением по умолчанию, для Пример: _ nonobjc:() =(). (19826275)
Переопределения методов, открытых до Objective-C в частных подклассах не предполагается, что это @objc, что приводит к сбою компилятора Swift. Явно добавьте @objc атрибут для любых таких методов переопределения. (19935352)
Символы из SDK недоступны при использовании Open Quickly в проект или рабочее пространство, которое использует Swift. (20349540)
то, что я сделал, просто добавляло "private" перед методом переопределения вроде этого:
private func performOperation(operation: Double -> Double) {
if operandStack.count >= 1 {
displayValue = operation(operandStack.removeLast())
enter()
}
}
Как уже было сказано, ObjC не поддерживает перегрузку метода (два метода с тем же именем), а в Swift 2 под Xcode 7 есть два варианта решения таких проблем. Одним из вариантов является переименование метода с использованием атрибута: @objc(newNameMethod:)
func methodOne(par1, par2) {...}
@objc(methodTwo:)
func methodOne(par1) {...}
другой вариант решения этой проблемы в Xcode 7+ заключается в применении атрибута @nonobjc
к любому методу, индексу или инициализатору
func methodOne() {...}
@nonobjc
func methodOne() {...}
Задача UIViewController
- это класс @objc
. При наследовании от UIViewController
, BugViewController
также является классом @objc
.
Это означает, что он должен соответствовать правилам селекторов Objective-C (имя метода). Методы func perform(operation: (Double) -> Double)
и func perform(operation: (Double, Double) -> Double)
имеют одинаковый селектор @selector(perform:)
. Это не разрешено.
Чтобы решить эту проблему, используйте разные имена: например, func perform1(operation: (Double) -> Double)
и func perform2(operation: (Double, Double) -> Double)
.
Я думаю, что лучший способ справиться с этим - дать вашим методам perform()
более описательные имена. Что делают эти методы? Как они изменяют состояние контроллера вида? Посмотрите на другие методы UIViewController
, чтобы понять стиль наименования методов или прочитать Имена методов должны быть выразительными и уникальными в пределах класса
Из https://developer.apple.com/library/ios/releasenotes/DeveloperTools/RN-Xcode/Chapters/xc6_release_notes.html в разделе "Примечания к выпуску Xcode 6.3" → "Быстрые изменения языка" вы найдете
Теперь Swift обнаруживает несоответствия между перегрузкой и переопределением в системе типа Swift и эффективным поведением, наблюдаемым через среду выполнения Objective-C.
Я получил ту же ошибку из-за наличия двух методов с одинаковой сигнатурой Obj-C:
static func prepareForUpSyncing(obj : NSManagedObject!) -> Bool
static func prepareForUpSyncing(objs : [NSManagedObject]!) -> Bool
Я не хотел отмечать один из них как @nonobjc из-за возможности непредвиденных последствий во время выполнения. (Кто-то может исправить меня, если нет возможности)
Решено с помощью функции внешнего имени параметра Swift (я сделал внешнее имя так же, как локальное имя) ко второму методу, который эффективно изменяет подпись метода Obj-c:
static func prepareForUpSyncing(objs objs : [NSManagedObject]!) -> Bool {