Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

214
Vistas
Odd Generics & Optional Behavior in Swift 4.2 after upgrading to iOS 12.2 (Xcode 10.2)

We have just updated Xcode to 10.2 (hence iOS 12.2 SDK) and started seeing odd behavior with respect to the behavior of Swift Generics and Optionals. We have kept the Swift version at 4.2, so no Swift 5 update. The only change was updating to Xcode 10.2 from Xcode 10.1.

Here is a sample code that illustrates the oddities. The comments show what has changed between versions. Ideally, there shouldn't be any changes.

class Phone<T> {}

extension Phone {
    class func create(initial: T? = nil) -> Phone<T> {
        if let _ = initial { print("Regular: Unwrapping worked.") }
        return Phone()
    }
}

extension Phone where T == Void {
    class func create(initial: T? = nil) -> Phone<T> {
        if let _ = initial { print("T == Void: Unwrapping worked.") }
        return Phone()
    }
}

var phone: Phone<Int?> = Phone()
var phone2: Phone<Int?> = Phone()
var phone3: Phone<Int?> = Phone()

// unwrapping works iOS 12.1, doesn't work in 12.2
phone = Phone.create(initial: Optional(nil))

// unwrapping works iOS 12.1, doesn't work in 12.2
phone2 = Phone.create(initial: Optional<Int?>(nil))

// doesn't compile in iOS 12.1, unwrapping works in iOS 12.2
phone3 = Phone.create(initial: Optional<Int>(nil))

// doesn't compile in iOS 12.1, unwrapping doesn't work in 12.2 (uses the T == Void function)
let phone4 = Phone.create(initial: Optional(nil))

We have gone through the release notes of Xcode 10.2 but haven't spotted any changes around Optionals or Generics. It is really hard to understand what is causing this change in behavior between versions.

It is especially very interesting how phone2 and phone3 behave differently. There are few odd things happening in the code sample above, so the question is if anyone knows what might have caused the behavioral changes in this release?

over 4 years ago · Santiago Trujillo
1 Respuestas
Responde la pregunta

0

This is due to SE-0213: Literal initialization via coercion which means that Optional(nil) is now treated as nil as Optional by the compiler. Previously with Optional(nil), you'd get a wrapped nil value e.g Int??.some(nil), however now you get just nil.

So for the following:

let phone: Phone<Int?> = Phone.create(initial: Optional(nil))

the compiler is treating it as:

let phone: Phone<Int?> = Phone.create(initial: nil as Optional)

which is equivalent to:

let phone: Phone<Int?> = Phone.create(initial: nil)

Because you've specified the generic parameter T to be Int?, the initial: parameter takes an Int??. Therefore by passing nil you're passing Int??.none, and therefore the unwrapping fails.

One way to restore the old behaviour is to specify .init explicitly in order to force the compiler to call the initialiser:

let phone: Phone<Int?> = Phone.create(initial: Optional.init(nil))

Now you're passing an Int??.some(nil) to the parameter and the unwrapping succeeds.

However I would question why you're dealing with doubly wrapped optionals in the first place – I would strongly encourage avoiding them unless absolutely necessary.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda