Diferencia entre Generics y AnyObject en Swift

Considere esta function myFilter que toma un argumento genérico y filtra la matriz en function del pnetworkingicado. Esto es lo mismo que la function de filter() proporcionada por Swift.

 func myFilter<T>(source: [T], pnetworkingicate:(T) -> Bool) -> [T] { var result = [T]() for i in source { if pnetworkingicate(i) { result.append(i) } } return result } 

¿Cómo es esto diferente,

 func myFilter(source: [AnyObject], pnetworkingicate:(AnyObject) -> Bool) -> [AnyObject] { var result = [AnyObject]() for i in source { if pnetworkingicate(i) { result.append(i) } } return result } 

¿No estamos logrando el punto de generics incluso en el último ejemplo?

Los generics son de tipo seguro, lo que significa que si pasas una cadena como un genérico y tratas de usar como un integer, el comstackdor se quejará y no podrás comstackr tu (lo cual es bueno). (Esto sucede porque Swift está utilizando la tipificación estática y puede proporcionarle un error de compilation )

Si usa AnyObject, el comstackdor no tiene idea de si el object puede tratarse como una cadena o como un integer. Te permitirá hacer lo que quieras con él (lo cual es malo).

Por ejemplo, si intenta pasar una Cadena cuando la Integer se usó anteriormente, la aplicación se bloqueará. (Esto sucede porque Swift está utilizando la tipificación dinámica y solo te dará un error de time de ejecución )

Generics básicamente le dice al comstackdor:

"Voy a darte un tipo más tarde y quiero que cumplas ese tipo en todas partes que especifique".

AnyObject básicamente le dice al comstackdor:

"No te preocupes por esta variable, no hay necesidad de hacer cumplir ningún tipo aquí, déjame hacer lo que quiera".

Nota : la respuesta de Icaro aún sería la respuesta aceptada, solo extiendo su explicación.

TL; DR : Verifique la respuesta de Icaro.

Sobre el uso de AnyObject Icaro correctamente:

No te preocupes por esta variable, no hay necesidad de hacer cumplir ningún tipo aquí, déjame hacer lo que quiera.

¿Qué significa esto? Tomemos el ejemplo del código en la pregunta (he avanzado un paso y AnyObject cambiado AnyObject a Any sin cambiar el significado de la pregunta):

 func myFilter(source: [Any], pnetworkingicate:(Any) -> Bool) -> [Any] { var result = [Any]() for i in source { if pnetworkingicate(i) { result.append(i) } } return result } 

Esto significa que la function myFilter toma en dos arguments una source y un pnetworkingicate cierre. Si observa de cerca, el contenido de la matriz de origen puede ser NADA. Y el argumento del pnetworkingicate cierre también puede ser NADA. Si tuviéramos que nombrar estos "CUALQUIER COSA", digamos CUALQUIER COSA1 y CUALQUIER COSA2, este enfoque no requiere que NADA1 sea igual a CUALQUIER COSA2.

Sentémonos y reflexione sobre las implicaciones de esto …

Digamos que queremos filtrar elementos de una matriz de integers y utilizar nuestro filter Any para esto

 var ints = [1,2,3,4,5] as [Any] var pnetworkingicate = { (a : Any) -> Bool in return (a as! Int) % 2 == 0 } let evens = myFilter(source: ints, pnetworkingicate:pnetworkingicate) 

Wow, eso funcionó, ¿no? ¿Todo sonrisas? No.

Observe cómo en la línea:

 return (a as! Int) % 2 == 0 

Estoy castigando a la fuerza a. Esta línea se bloquearía si a fuera cualquier otra cosa que un Int . Pero su uso está justificado; después de todo, queremos simplemente filtrar el Int s y soy lo suficientemente inteligente como para usar solo una matriz de Int s.

Pero, como digo, soy un progtwigdor ingenuo, hago esto:

 var ints = [1,2,3,4,5,"6"] as [Any] var pnetworkingicate = { (a : Any) -> Bool in return (a as! Int) % 2 == 0 } let evens = myFilter(source: ints, pnetworkingicate:pnetworkingicate) 

Esto comstack felizmente, pero falla en el time de ejecución. Si solo hubiera una forma, donde el comstackdor me diría que esta línea …

 var ints = [1,2,3,4,5,"6"] 

… fue defectuoso, no habríamos tenido un crash. ¡Lo habría arreglado de inmediato!

Resulta que hay. Genéricos Para citar nuevamente a Icaro,

Voy a darte un tipo más tarde y quiero que cumplas ese tipo en todas partes que especifique.

 func myFilter<T>(source: [T], pnetworkingicate:(T) -> Bool) -> [T] { var result = [T]() for i in source { if pnetworkingicate(i) { result.append(i) } } return result } var ints = [1,2,3,4,5,6] var pnetworkingicate = { (a : Int) -> Bool in return a % 2 == 0 } let evens = myFilter(source: ints, pnetworkingicate:pnetworkingicate) 

Este nuevo filter es increíble. No me deja hacerlo:

let evens = myFilter(source: ints, pnetworkingicate:pnetworkingicate) porque, los types del pnetworkingicate y el source no coinciden. Tiempo de compilation de error.

Generics es genérico de esta manera: en este ejemplo específico, mientras que al momento de escribir la function myFilter , no es necesario dar un tipo de source o el argumento que toma el pnetworkingicate , es T, es NADA. Pero una vez que digo que la source es una matriz de CUALQUIER COSA, TIENES que asegurarte de que el argumento que acepta el pnetworkingicate sea ​​el mismo CUALQUIER COSA. Con el trasbackground de nuestra nomenclatura anterior NADA 1, NADA 2, podemos decir que los generics obligan a NADA 1 a ser igual a NADA2

Considere que en la primera function T no es un tipo, como es AnyObject, sino una variable tipo ; esto significa que en la primera function puede pasar una matriz de valores de cualquier tipo como primer parámetro, pero un pnetworkingicado que opera solo en valores de ese tipo específico como segundo parámetro. Es decir, puede pasar una matriz de cadenas y un pnetworkingicado en cadenas, o una matriz de integers y un pnetworkingicado en integers, mientras que no puede pasar una matriz de integers y un pnetworkingicado en cadenas. Por lo tanto, se garantiza que el cuerpo de la function sea correcto para lo que concierne a los types.

En cambio, en el segundo ejemplo puede pasar un valor de cualquier tipo y un pnetworkingicado que funcione en cualquier tipo (¡posiblemente diferente!), De modo que, si el pnetworkingicado fuera invocado en el cuerpo de la function con el valor del primer parámetro, entonces podría ocurrir un error de tipo dynamic. Afortunadamente, el typechecker Swith marca la llamada del pnetworkingicado como error de tipo, para evitar esta posibilidad.