protocol extension associated swift swift-extensions

swift - extension - ¿Cómo agregar una extensión de cadena opcional?



swift protocol extension (8)

Extensiones en Optional que devuelven una String

A partir de Swift 3, no puede restringir directamente un método de extensión a una String opcional. Puede lograr el resultado equivalente con protocolos como explica la respuesta de Daniel Shin.

Sin embargo, puede crear un método de extensión en un Opcional de cualquier tipo y he encontrado algunos métodos útiles que tienen un valor de retorno de String . Estas extensiones son útiles para registrar valores en la consola. He usado asStringOrEmpty () en una String opcional cuando quiero reemplazar un posible nulo con una cadena vacía.

extension Optional { func asStringOrEmpty() -> String { switch self { case .some(let value): return String(describing: value) case _: return "" } } func asStringOrNilText() -> String { switch self { case .some(let value): return String(describing: value) case _: return "(nil)" } } }

Ejemplo de uso:

var booleanValue: Bool? var stringValue: String? var intValue: Int? print("booleanValue: /(booleanValue.asStringOrNilText())") print("stringValue: /(stringValue.asStringOrNilText())") print("intValue: /(intValue.asStringOrNilText())") booleanValue = true stringValue = "text!" intValue = 41 print("booleanValue: /(booleanValue.asStringOrNilText())") print("stringValue: /(stringValue.asStringOrNilText())") print("intValue: /(intValue.asStringOrNilText())")

Salida de consola:

booleanValue: (nil) stringValue: (nil) intValue: (nil) booleanValue: true stringValue: text! intValue: 41

Optional diferente al puntero nulo

Estas extensiones ilustran que un Optional es diferente que un puntero nulo. Un Optional es una enum de un tipo especificado ( Wrapped ) que indica que contiene o no un valor. Puede escribir una extensión en el "contenedor" Optional aunque no contenga ningún valor.

Extracto de la Declaración Opcional Swift

enum Optional<Wrapped> : ExpressibleByNilLiteral { /// The absence of a value. case none /// The presence of a value, stored as `Wrapped`. case some(Wrapped) ... }

En el código, la ausencia de un valor generalmente se escribe utilizando el literal nil lugar del caso de enumeración explícito .none .

Puede crear una extensión de cadena de esta manera:

extension String { func someFunc -> Bool { ... } }

pero ¿y si quieres que se aplique a una cadena opcional?

var optionalString :String? = "" optionalString!.someFunc() /* String? does not have a member someFunc */


Desde Xcode 9.3, puede usar esta ligera modificación de la respuesta de @ Vladyslav:

extension Optional where Wrapped == String { var isEmpty: Bool { return self?.isEmpty ?? true } }


En Swift 3.1 también puede agregar una extensión a los valores opcionales:

extension Optional where Wrapped == String { var isBlank: Bool { return self?.isBlank ?? true } }


En Swift 4.1, estaba obteniendo un Optional is ambiguous for type lookup in this context error de compilación de Optional is ambiguous for type lookup in this context . Para solucionarlo, debe agregar explícitamente el espacio de nombres Swift al tipo:

extension Swift.Optional where Wrapped == String { var isBlank: Bool { return self?.isBlank ?? true } }


Puedes hacerlo así:

protocol OptionalType { typealias A; var opt: A? { get } } extension Optional: OptionalType { var opt: A? { return self } } protocol StringType { var get: String { get } } extension String: StringType { var get: String { return self } } extension Optional where Wrapped: StringType { func getOrElse(s: String) -> String { return self.opt?.get ?? s } }

Y:

let optStr: String? = nil optStr.getOrElse("hello world")

La razón por la que no puede restringir Optional o String para ese asunto, es porque son struct . Al hacer un pseudo-protocolo para cada uno, ahora podemos restringir lo que queramos.

Siento que Swift ha renunciado a muchas cosas solo para facilitar que los principiantes aprendan o tal vez el idioma aún no ha madurado lo suficiente.


encontrado un truco rápido 3

class A{ var name:String!; init(_ name:String?){ self.name = name; } } extension Optional where Wrapped == String { func compareText(_ other:String?)->Bool{ switch (self,other){ case let(a?,b?): return a < b; case (nil,_): return true; default: return false; } } } let words:[A] = [A("a"),A(nil),A("b"),A("c"),A(nil)]; // let sorted = words.sorted{ 0.name.compareText($1.name) } // trick let sorted = words.sorted{ ($0.name as String?).compareText($1.name) } print(sorted.map{$0.name});


Actualización: para una solución alternativa que funciona con Swift 2 y superior, vea la respuesta de Daniel Shin

Una cadena opcional no es en sí misma un tipo, por lo que no puede crear una extensión en un tipo opcional. En Swift, un Optional es solo una enumeración (más un poco de azúcar sintáctica) que puede ser None o Some que envuelve un valor. Para usar su método de Cadena, debe desenvolver su Cadena optionalString . Puede usar fácilmente el encadenamiento opcional para lograr esto:

optionalString?.someFunc()

Si optionalString no es nil , se someFunc a someFunc . Una forma alternativa (menos concisa) de hacer esto es usar el enlace opcional para establecer si optionalString tiene o no un valor antes de intentar llamar al método:

if let string = optionalString { string.someFunc() // `string` is now of type `String` (not `String?`) }

En su ejemplo de los comentarios a continuación, no necesita anidar múltiples declaraciones if , puede verificar si la cadena opcional es una cadena vacía en una sola if :

if optionalString?.isEmpty == true { doSomething() }

Esto funciona porque la expresión optionalString?.isEmpty devuelve un Bool opcional (es decir, true , false o nil ). Entonces, doSomething() solo se llamará si optionalString no es nil , y si esa cadena está vacía.

Otra alternativa sería:

if let string = optionalString where string.isEmpty { doSomethingWithEmptyString(string) }


extension Optional where Wrapped == String { var isNil: Bool { return self == nil }

La respuesta anterior (escrita por @Vlad Hatko) funciona bien pero en Swift 4 hay algunos problemas, así que la cambié a esto.