¿El uso de la inferencia Swift 3 @objc en el modo Swift 4 está en desuso?

485

Brevemente, mientras uso Xcode 9 Beta, me he encontrado con la siguiente advertencia:

El uso de la inferencia Swift 3 @objc en el modo Swift 4 está en desuso. Dirija las advertencias de inferencia obsoleta @objc, pruebe su código con el registro "Uso de inferencia obsoleta Swift 3 @objc" habilitado y desactive la inferencia Swift 3 @objc. **

Después de un poco de investigación, todavía no tengo idea de cómo solucionar el problema. Agradecería mucho cualquier consejo sobre cómo solucionar este problema, así como una explicación de lo que está sucediendo.

Mi objetivo es comprender mejor lo que está sucediendo con mi código.

DaleK
fuente
44
Realmente no obtengo del mensaje de advertencia qué objeto lo está causando. Xcode simplemente no dice en qué línea está ese objeto. ¿Algún consejo para saber de dónde viene esta advertencia?
olyv

Respuestas:

816

Eliminé esta advertencia cambiando la configuración de compilación "Swift 3 @objc Inference" de mis objetivos a "Predeterminado".

Deshabilite la inferencia de Swift 3 @objc en Xcode9

De este artículo :

Antes de Swift 4, el compilador hizo algunas declaraciones Swift disponibles automáticamente para Objective-C . Por ejemplo, si se subclasificó de NSObject, el compilador creó puntos de entrada Objective-C para todos los métodos en tales clases. El mecanismo se llama inferencia @objc.

En Swift 4, dicha inferencia automática @objc está en desuso porque es costoso generar todos esos puntos de entrada de Objective-C. Cuando la configuración "Swift 3 @objc Inference" se establece en "On", permite que el código anterior funcione. Sin embargo, mostrará advertencias de desaprobación que deben abordarse. Se recomienda "corregir" estas advertencias y cambiar la configuración a "Predeterminado" , que es el valor predeterminado para los nuevos proyectos de Swift.

Consulte también esta propuesta de Swift para obtener más información.

Evgenii
fuente
55
Gracias Evgenii ¿Es esta una solución a largo plazo?
DaleK
66
@DaleK sí, eso creo. Según la propuesta de Swift que mencioné en mi respuesta, la inferencia objc está en desuso. La configuración "Swift 3 objc Inference" solo está presente en los proyectos que se migraron de versiones anteriores de Swift. Si se crea un nuevo proyecto, la configuración ya no está presente, lo que significa que la inferencia de objc está desactivada. Se recomienda abordar las advertencias de inferencia objc y configurarlo en "Desactivado".
Evgenii
44
El mensaje de información en XCode sugiere que: "El uso de la @objcinferencia Swift 3 en el modo Swift 4 está en desuso. Por favor, aborde las @objcadvertencias de inferencia en desuso , pruebe su código con el @objcregistro " Uso de inferencia en desuso Swift 3 "habilitado y desactive la @objcinferencia Swift 3 ". ¿Alguna idea de dónde habilitar dicho @objcregistro de inferencia Swift 3 ?
courteouselk
44
@courteouselk, de acuerdo con la propuesta de Swift, se puede establecer la variable de entorno SWIFT_DEBUG_IMPLICIT_OBJC_ENTRYPOINT en valores del 1 al 3 para ver los usos de los puntos de entrada de Objective-C en los registros.
Evgenii
14
Solo para agregar: debe hacer esto para todos los tagets de compilación, no solo para el proyecto.
Krivvenz
270

- ¿Qué es la @objcinferencia? Que esta pasando?

En Swift 3, el compilador deduce @objcen varios lugares para que no tenga que hacerlo. En otras palabras, ¡se asegura de agregar @objcpara usted!

En Swift 4, el compilador ya no hace esto (tanto). Ahora debe agregar @objcexplícitamente.

Por defecto, si tiene un proyecto anterior a Swift 4, recibirá advertencias al respecto. En un proyecto Swift 4, obtendrá errores de compilación. Esto se controla mediante la SWIFT_SWIFT3_OBJC_INFERENCEconfiguración de compilación. En un proyecto anterior a Swift 4, esto se establece en On. Recomendaría establecer esto en Default(o Off), que ahora es la opción predeterminada en un nuevo proyecto.

Tomará algún tiempo convertir todo, pero dado que es el valor predeterminado para Swift 4, vale la pena hacerlo.

- ¿Cómo detengo las advertencias / errores del compilador?

Hay dos formas de convertir su código para que el compilador no se queje.

Una es usar @objcen cada función o variable que deba exponerse al tiempo de ejecución de Objective-C:

@objc func foo() {

}

El otro es usarlo @objcMembersmediante una Classdeclaración. Esto se asegura de agregar automáticamente @objca TODAS las funciones y variables en la clase. Esta es la manera fácil, pero tiene un costo, por ejemplo, puede aumentar el tamaño de su aplicación al exponer funciones que no necesitaban estar expuestas.

@objcMembers class Test {

}

- ¿Qué es @objcy por qué es necesario?

Si introduce nuevos métodos o variables en una clase Swift, marcándolos como @objcexpuestos al tiempo de ejecución de Objective-C. Esto es necesario cuando tiene un código Objective-C que usa su clase Swift o, si está usando características de tipo Objective-C como Selectors. Por ejemplo, el patrón de acción objetivo: button.addTarget(self, action:#selector(didPressButton), for:.touchUpInside)

- ¿Por qué no marcaría todo @objc?

Hay aspectos negativos que vienen con marcar algo como @objc:

  • Aumento del tamaño binario de la aplicación.
  • Sin sobrecarga de funciones

Tenga en cuenta que este es un resumen de muy alto nivel y que es más complicado de lo que escribí. Recomendaría leer la propuesta real para obtener más información.

Fuentes:

kgaidis
fuente
@objcno implica despacho dinámico, Swift es libre de usar despacho estático o virtual (y posiblemente ejecutar código diferente como resultado). La dynamicpalabra clave es necesaria para obligar a Swift a utilizar el despacho dinámico.
Kevin
77
¿Hay otras formas de agregar acción al botón? Si es @objcdepricated, ¿qué debemos usar?
Aznix
55
@Stefan, sí, puede haber bastante para convertir. Dividirlo en etapas. Deja SWIFT_SWIFT3_OBJC_INFERENCEal On. Convierte a Swift 4. Luego aborda las @objccosas. Para hacerlo simple, siga las reglas básicas: SI la clase Swift se usa en el código Objc-C (a través del encabezado de puente), use @objcMembers, de lo contrario, agregar uno por uno @objc. Simplemente use la búsqueda Xcode para averiguar si se llama a la clase Swift desde cualquier .marchivo. Esto debería hacer que la conversión sea relativamente indolora.
kgaidis
55
@DaleK esta respuesta debe ser aceptada. Suprimir advertencias y hacer que las cosas funcionen como estaban en Swift 3 es una opción, pero en mi humilde opinión, no es la mejor. Es importante entender por qué @objccambió en Swift 4 y luego tomar la decisión de arreglar el proyecto y mantenerlo igual.
derpoliuk
2
Gracias por esta breve explicación
Schmoudi
48

El migrador no puede identificar todas las funciones que necesitan los thunk de Objective-C inferidos de @objc marcados como obsoletos para ayudarlo a encontrarlos.
• Cree advertencias sobre métodos
obsoletos.

ingrese la descripción de la imagen aquí

Hassan Taleb
fuente
1
Entonces, ¿qué debo hacer con @objc? eliminarlo? ¿dejalo? Ya lo eliminé. y recibí esas advertencias, ¿así que tengo que agregarlas? que en el paso 3 debo hacer con eso?
Shial
Agregue @objc justo antes de func
Hassan Taleb
1
¿De qué se trata el paso 3? Podría agregar algunas descripciones :)
Shial
Y en mi caso, recibo esta advertencia, pero no se señala ningún código. Hay dos métodos marcados con @objc y parecen ser los únicos que lo necesitan. Lo cambié a Predeterminado y sigo recibiendo advertencias durante la compilación.
Maury Markowitz
12

Recibí esta advertencia con la configuración "Swift 3 @objc Inference" = "Predeterminado". Entonces me di cuenta de que estaba configurado para el Proyecto, no para el objetivo. Por lo tanto, asegúrese de tener la configuración "Predeterminada" en su objetivo para deshacerse de la advertencia.

Dmitry
fuente
Perdí 20 minutos buscando resolver el error incluso después de cambiar a Predeterminado en la configuración del proyecto. Usted señaló exactamente que también debe cambiarse en el objetivo.
SkrewEverything
8

Simplemente puede pasar a "predeterminado" en lugar de "ON". Parece más adherente a la lógica de Apple.

(pero todos los otros comentarios sobre el uso de @objsiguen siendo válidos).

ingconti
fuente
7

De hecho, se deshará de esas advertencias deshabilitando Swift 3 @objc Inference. Sin embargo, pueden surgir problemas sutiles. Por ejemplo, KVO dejará de funcionar. Este código funcionó perfectamente en Swift 3:

for (key, value) in jsonDict {
    if self.value(forKey: key) != nil {
        self.setValue(value, forKey: key)
    }
}

Después de migrar a Swift 4 y configurar "Swift 3 @objc Inference" de manera predeterminada, ciertas funciones de mi proyecto dejaron de funcionar . Me tomó un poco de depuración e investigación para encontrar una solución para esto. Según mi mejor conocimiento, estas son las opciones:

  • Habilite "Inferencia Swift 3 @objc" (solo funciona si migró un proyecto existente desde Swift 3) ingrese la descripción de la imagen aquí
  • Marque los métodos y propiedades afectados como @objc ingrese la descripción de la imagen aquí
  • Vuelva a habilitar la inferencia ObjC para toda la clase usando @objcMembers ingrese la descripción de la imagen aquí

Volver a habilitar la inferencia @objc te deja con las advertencias, pero es la solución más rápida. Tenga en cuenta que solo está disponible para proyectos migrados desde una versión anterior de Swift. Las otras dos opciones son más tediosas y requieren un poco de excavación de código y pruebas exhaustivas.

Ver también https://github.com/apple/swift-evolution/blob/master/proposals/0160-objc-inference.md

Karoly Nyisztor
fuente
7

Soy un desarrollador de iOS ocasional (pronto será más) pero todavía no pude encontrar la configuración según la otra respuesta (ya que no tenía ese elemento de Llavero que muestra la respuesta), así que ahora que lo encontré pensé Podría agregar esta instantánea con las ubicaciones resaltadas en las que deberá hacer clic y buscar.

  1. Comience en la esquina superior izquierda
  2. Elija el icono de la carpeta del proyecto
  3. Elija su nombre de proyecto principal debajo del icono de la carpeta del proyecto.
  4. Elija Configuración de compilación en el lado derecho.
  5. Elija su proyecto en OBJETIVOS.
  6. Desplácese muy hacia abajo (o busque la palabra inferencia en el cuadro de texto de búsqueda)

Encontrar la configuración

raddevus
fuente
6

Puede intentar "Actualizar pod" y / o "limpiar el aleteo"

También configuré esta configuración en xcode.

La configuración de la interfaz Objective-C es la siguiente:

Configuración de la interfaz ObjectiveC

wisekiddo
fuente
2

Inferencia Swift 3 @objc El uso de la inferencia Swift 3 @objc en el modo Swift 4 está en desuso. Dirija las advertencias de inferencia obsoleta @objc, pruebe su código con el registro "Uso de inferencia obsoleta Swift 3 @objc" habilitado, y luego desactive la inferencia cambiando la configuración de compilación "Inferencia Swift 3 @objc" a "Predeterminado" para "XMLParsingURL" objetivo.

llegué a la

  1. El primer paso consiguió la configuración de compilación

  2. Buscar para generar inferencia de configuración

  3. cambiar swift 3 @objc Inferencia Predeterminado

ingrese la descripción de la imagen aquí

Praveen Kumar
fuente
1

Todo lo que necesita es ejecutar una prueba, esperar hasta que termine, después de eso vaya a Configuración de compilación, Buscar en Inferencia de configuración de compilación, cambie Swift 3 @objc Inference a (Predeterminado). Eso es todo lo que hice y funcionó perfectamente.

Acasey
fuente
0

¿El uso de la inferencia Swift 3 @objc en el modo Swift 4 está en desuso?

use func call @objc

func call(){

foo()

}

@objc func foo() {

}
Puji Wahono
fuente
0

Además de lo que dijo @wisekiddo, también puede modificar su configuración de compilación en el project.pbxprojarchivo configurando la Inferencia Swift 3 @obj como predeterminada SWIFT_SWIFT3_OBJC_INFERENCE = Default;para sus sabores de compilación (es decir, depurar y liberar), especialmente si viene de otro entorno además de Xcode

DaveNOTDavid
fuente