Swift Any & AnyObject Types

9 minute read

Bu yazımda şu konuları anlatmaya çalışacağım:

  • Any nedir? Hangi amaçla kullanılmaktadır?
  • Any & AnyObject Kullanım Alanları
  • Swift compiler arka planda neler yapıyor?
  • Any türünden bir değişkenin doğru kullanımı
  • Any bir referans mıdır? Compiler burada nasıl davranır?
  • Any türden diziler tanımlayabilir miyiz?
  • Any ile AnyObject arasında ki fark nedir?

Swift dili geliştirilirken birçok programlama dilinden yararlanılmış. Diğer dillerin dizaynından, sentaks yapısından, iyi yönlerinden faydanılarak oluşturulmuş.

Swift programlama dilinin multi paradigm olduğunu söylemiştik. Yani prosedural, object oriented, functional programlama teknikleri ile uygulama geliştirebiliyoruz.

Java, C# programlama dillerinde herşey en üst sınıf Object’ten oluşmaktadır. C++ dilinde ise böyle bir teknik yoktur. Swift dili burada C++ diline benzemektedir.


Any nedir? Hangi amaçla kullanılmaktadır?

  • Any öncelikle bir türdür.
  • Herhangi türden bir nesneye Any isimli bir türe atayabiliriz.
  • Any türünden nesne yaratamayız. Burada ki çözüm yolu referans bildirmektir çünkü her türden nesne any türünden referansa atanabilir. Hemen örneğe bakalım:
 1var ival: Int = 10
 2var dval: Double = 9.9
 3var sval: String = "Kerem"
 4
 5struct ProgLang{
 6    // KODLAR
 7}
 8
 9class FavLang{
10    // KODLAR
11}
12
13
14var anyTypes: Any
15
16anyTypes = ival
17anyTypes = dval
18anyTypes = sval
19anyTypes = ProgLang()
20anyTypes = FavLang()

Kodu derlediğimiz zaman hiçbir hata almadığınızı göreceksiniz. Burada dikkatinizi çekmek istediğim bir nokta var. anyTypes isimli Any türüne referans haricinde(class), struct değişkenleride atayabiliyoruz.


Swift compiler bu işlemi nasıl yapıyor?

  • Any türüne bir yapı veya enum atandığı zaman “boxing conversion” yoluyla HEAP alanında bir kopyasını çıkarır.
  • Any referansı artık HEAP alanında ki o kopya değeri gösterir.

Senaryo: Parametresi Any türünden olan bir fonksiyon yazalım. Bu fonksiyonu herhangi türden bir değer ile çağıralım.

 1var ival: Int = 10
 2var dval: Double = 9.9
 3var sval: String = "Kerem"
 4
 5struct Lispic {
 6    // ...
 7}
 8
 9class LearnSwift {
10    // ...
11}
12
13func anyType(herhangiBirTip x: Any) {
14    print(type(of: x))
15}
16
17anyType(herhangiBirTip: ival)   // Int
18anyType(herhangiBirTip: dval)   // Double
19anyType(herhangiBirTip: sval)   // String
20anyType(herhangiBirTip: Lispic())   // Lispic
21anyType(herhangiBirTip: LearnSwift())   // LearnSwift

Sonuç: Fonksiyonlar Any türünden olabilir ve herhangi türden bir değişken ile çağırabiliriz.


Any türünden bir değişkenin kullanımı

  • Tür dönüşümü yapmadan kullanmamalıyız.
  • Tür dönüşümünü as!(Forced downcasting) yada as?(Conditional downcasting) operatorlerini kullanarak yapabiliriz.

Senaryo: Bir User sınıfı tanımlayalım. Sınıf isim, yaş ve favori programlama dili özelliklerinden oluşsun. Sınıfın display diye bir fonksiyonu olsun. Biz Any türden bir değişkene oluşturduğumuz sınıfı atıp, display fonksiyonuna erişmeye çalışalım.

 1class User {
 2    var name: String
 3    var age: Int
 4    var favProgLang: String
 5
 6    init(name: String, age: Int, favProgLang: String){
 7        self.name = name
 8        self.age = age
 9        self.favProgLang = favProgLang
10    }
11
12    func display(){
13        print("Isim -> \(self.name)\nYas -> \(self.age)\nFavori Programlama Dili -> \(self.favProgLang)")
14    }
15}
16
17
18var anyType: Any
19anyType = User(name: "Kerem", age: 28, favProgLang: "Lisp")
20anyType.display() // Value of type 'Any' has no member 'display'
21
22var anyType: Any
23anyType = User(name: "Kerem", age: 28, favProgLang: "Lisp")
24var res = anyType as! User
25res.display()

Sonuç: Hatadan anladığımız gibi Any türünden bir değişkeni direk olarak işleme sokamıyoruz. Tür dönüşümü yapmamız gerekiyor.


Any bir referans mıdır? Compiler burada nasıl davranır?

  • Any bir referanstır.
  • Swift dilinde bir referans HEAP alanında ki bir nesneyi gösterir.
  • Referans ise stack alanında yer alır. Yani bir yapıyı any türünden bir refaransa atadığımızda boxing conversion gerçekleşir. Yukarıda da dediğimiz gibi swift compiler HEAP’te yapı değişkeninin bir kopyasını oluşturur.
  • Any referansı Stack alanındadır ve HEAP alanında ki nesneyi gösterir hale gelir.

Bu söylediğimizi ispatlayan ufak bir kod yazalım.

 1func printAddress<T>(of pointer: UnsafePointer<T>) {
 2    print(pointer)
 3}
 4
 5var ival: Int = 3
 6printAddress(of: &ival) // 0x00000001003edec0
 7var anyType: Any
 8
 9anyType = ival
10printAddress(of: &anyType) // 0x00000001003edec8
11// anyType ival nesnesini gostermiyor, ival nesnesinin kopyasini gosteriyor
12// Hemen ival nesnesinde degisiklik yapiyorum
13ival = 999
14
15// Eger anyType ival nesnesini gosteriyorsa degeri 999 olmasi gerekiyor
16print(anyType as! Int) // 3 degerini gosteriyor
17

Sonuç: Bellek adreslerinde de anlaşıldığı gibi aynı nesneyi değil, kopyasını göstermektedir.


Any türden diziler tanımlayabilir miyiz?

  • Any türünden diziler tanımlayabiliriz.
  • Dizileri dolaşırken dikkat etmemiz gereken nokta is operatörü ile dizi elemanlarının türlerini belirlememiz gerekiyor.
  • İstenilirse Any? türünden de referanslar tanımlayabiliriz. Bu sayede referanslara nil atayabiliriz.

Any ile AnyObject arasında ki fark nedir?

Any & AnyObject

Yukarıda ki grafikte herşey çok açık duruyor. AnyObject türüne referans türlerine ilişkin nesneler atayabiliyoruz. Any türüne ise her türden nesne atayabiliyoruz.


Kaynaklar:

How to share structs using boxing?

Type casting in swift : difference between is, as, as?, as!

Swift Type Casting – as, is, Any, AnyObject

Mastering Swift: Tips About Array and Dictionary Literals

What Is Any in Swift

Any Object