Swift Type Casting (Tip Dönüşümleri)

Merhaba arkadaşlar, Swift dersleri serimize Swift Type Casting (Tip Dönüşümleri) ile devam ediyoruz. Type Casting Swift programlama dili içerisinde yaygın olarak kullanılmaktadır. Birçoğumuz bunu kullanıyoruz ancak ne zaman hangi anahtar kelimeleri kullanacağız, as nedir, Any nedir, AnyObject nedir gibi sorulara ve daha fazlasına aşağıda cevap vereceğiz. O halde hemen başlayalım:

Swift Type Casting

Type(Tip) nedir?

Her şeyden önce tiplerden çok kısa bahsedelim. Aslında işin özünde tipler var; adı üstünde type casting yani tipleri dönüştürmek. Swift programlama dili farklı türdeki verileri tutabilmek için tipleri kullanır. Tiplere örnek olarak :

String
Int
Bool
struct Araba // Kendi oluşturduğumuz araba structı da bir tiptir.

vs. verilebilir. Hepsi farklı tiplerdir. Swift programlama dilinde oluşturacağımız her yeni değişken veya sabit için bir tip belirtmek zorundayız. Belirtmediğimiz durumlarda ise literal değerlerine göre derleyici bu değişken veya sabitlere bizim yerimize tiplerini vermektedir. Şu şekilde örnekleyebiliriz:

var sampleString: String = "örnek"     //-> explicit
var sampleStringWithoutType = "örnek"  //-> implicit

Tipini belirtmediğimiz ikinci değişkeni değiştirmeye çalışalım:

sampleStringWithoutType = 0

Değişkenimizin tipini belirmemiş olsak dahi, derleyici bu değişkenin ilk aldığı değerde string olduğunu belirliyor ve daha sonra farklı bir tipte atama yapamıyoruz.

Type Casting ( Tip Dönüşümü) nedir?

Type casting ise bir tipi başka bir tip gibi davranmaya zorlamak veya bir tipi control etmek için kullanılır. İlk önce tipleri nasıl kontrol ettiğimize bir göz atalım:

Checking Type (Tipi Kontrol Etmek)

Swift programlama dili ile tipleri kontrol etmek için “is” anahtar kelimesini kullanırız. Konunun anlaşılırlığını artırmak için örnek bir senaryo hazırlıyorum, şöyle ki; bir araba fabrikamız var ve farklı tiplerde araba üretiliyor. Bize bu fabrikadan gelen bir dizi araç var ve biz bu araçların tiplerini kontrol etmek istiyoruz. Örnek senaryo için gerekli fabrikayı aşağıya kuralım:

        protocol Araba {
            var kasa: KasaTipi { get }
        }

        enum KasaTipi{
            case Sedan
            case Hatchback
            case Coupe
        }

        struct SedanAraba: Araba{

            var kasa: KasaTipi{
                return .Sedan
            }
        }

        struct HatchbackAraba: Araba{

            var kasa: KasaTipi{
                return .Hatchback
            }
        }

        struct CoupeAraba: Araba{

            var kasa: KasaTipi{
                return .Coupe
            }
        }

Bu fabrikadan oluşan biz dizi oluşturalım ve daha sonra tiplerimizi kontrol edelim:

        var arabalar = [Araba]()
        arabalar.append(SedanAraba())
        arabalar.append(HatchbackAraba())
        arabalar.append(CoupeAraba())
        arabalar.append(SedanAraba())
        arabalar.append(HatchbackAraba())
        arabalar.append(SedanAraba())


        for araba in arabalar{
            if araba is SedanAraba{
                print("Bu arabanın kasası \(araba.kasa)")
            }else if araba is HatchbackAraba{
                print("Bu arabanın kasası \(araba.kasa)")
            }else if araba is CoupeAraba{
                print("Bu arabanın kasası \(araba.kasa)")
            }else{
                print("Böyle bir araba bulunmamaktadır")
            }
        }

Yukarıdaki örneğin konsol çıktısı şu şekildedir:

Bu arabanın kasası Sedan
Bu arabanın kasası Hatchback
Bu arabanın kasası Coupe
Bu arabanın kasası Sedan
Bu arabanın kasası Hatchback
Bu arabanın kasası Sedan

Beklediğimiz cevap da bu idi. Swift programlama dilinde tipleri bu şekilde kontrol edebiliriz. Şimdi de type casting işlemine bakalım.

Swift Type Casting

Type casting iki farklı başlıkta incelenebilir. UpCasting ve DownCasting. Her iki işlemi yaparken de “as” anahtar kelimesini kullanırız ancak downcast ederken “as” anahtar kelimesi ile birlikte “!” veya “?” işaretlerinden bir tanesi kullanılır.

Upcasting

Bir nesneyi upcast etmek demek alt sınıftan(subclass) üst sınıfa(superclass) dönüştürmek(benzetmek) demektir. Sınıfı aşağıdan yukarıya doğru dönüştürmeye, ya da benzetmeye diyelim, çalıştığımız durumlar için bu anahtar kelimeyi kullanırız ancak neredeyse her durumda bunu implicit kullanırız. Yani yazmasak da derleyici bir hata vermez çünkü nereye upcast ettiğimizi bilir. Örnek vermek gerekir ise:

let button = UIButton()
let label = UILabel()
let views = [label, button]
        
for view in views {
   self.view.addSubview(view as UIView)
}

Burada “as UIView” kısmını çıkardığımızda herhangi bir problem ile karşılaşmayız çünkü UIButton ve UILabel, UIView’dan türetilmiş birer view’dır.

Downcasting

Upcasting için subclasstan superclassa doğru, yani yukarıya doğru bir benzeme (upward) var iken, downcastingte durum tam tersidir. Superclass’tan oluşanan nesne subclassa benzemeye çalışır. Downcasting işlemini iki başlıkta inceleyeceğiz; force downcasting ve conditional downcasting. Tam şu anda optional dersini hatırlamıyorsanız kontrol etmenizde fayda var.

Force Downcasting

Force downcasting yapabilmemiz için kullanacağımız anahtar kelime “as!” olacaktır. Önce bir örnek yazıp bunun üzerinden anlatmak istiyorum:

enum VitesTipi{
    case manuel
    case otomatik
}

struct SedanAraba: Araba{
    
    var kasa: KasaTipi{
        return .Sedan
    }
    var vitesTipi: VitesTipi
}

Sedan araba sınıfımızı yukarıdaki şekilde güncelleyelim.

let araba: Araba = SedanAraba(vitesTipi: .manuel)

Yukarıda üst sınıftan oluşturduğumuz araba nesnesinin içine alt sınıf olan SedanAraba sınıfının bir nesnesini atadık. Bu haliyle araba nesnesi ile birlikte sedan araba içerisine eklediğimiz vites tipi parametresine erişemeyeceğiz. Çünkü elimizde bir araba nesnesi var ve bu nesnenin vitesTipi adında bir değişkeni yok. Peki erişmek için ne yapmalıyız:

let sedanAraba = araba as! SedanAraba
print(sedanAraba.vitesTipi) // printed -> manuel

Erişmek için araba nesnemizi SedanAraba sınıfımıza cast etmeliyiz. Force downcast ettiğimiz durumda optional olmayan vitesTipi parametresini elde ederiz.

Conditional Downcasting

Yukarıdaki örnekten devam etmek gerekirse conditional downcast ettiğimiz durumda elimizde optional bir nesnemiz olur.

let sedanArabaConditional = araba as? SedanAraba
print(sedanArabaConditional?.vitesTipi) // printed -> Optional(ProjeAdı.VitesTipi.manuel)

Type casting kullanımı yukarıdaki gibidir.

Any ve AnyObject Arasındaki farklar

Tipi belirli olmayan nesneler için Swift programlama dili iki farklı tip sunar; Any ve AnyObject. Any cast etmek için her tip ile (sınıf, struct vb.) kullanılabilirken, AnyObject sadece sınıfları cast etmek için kullanılır. Aşağıda bunları örnekler üzerinden inceleyelim:

var anyDizisi = [Any]()
anyDizisi.append(3)
anyDizisi.append("test")
anyDizisi.append(7.77)
anyDizisi.append(SedanAraba(vitesTipi: .manuel))

print(anyDizisi)
[3, "test", 7.77, DelegatePattern.SedanAraba(vitesTipi: DelegatePattern.VitesTipi.manuel)]
var anyDizisi = [AnyObject]()
anyDizisi.append(3 as AnyObject)
anyDizisi.append("test"  as AnyObject)
anyDizisi.append(7.77  as AnyObject)
anyDizisi.append(SedanAraba(vitesTipi: .manuel)  as AnyObject)
        
print(anyDizisi)
[3, test, 7.77, DelegatePattern.SedanAraba(vitesTipi: DelegatePattern.VitesTipi.manuel)]

Yukarıda aynı dizinin Any ve AnyObject’e cast edilmiş halleri var. İkisi arasında bir miktar fark var aslında. Yukarıdaki ilk cümlemizde bunu söylemiştik. AnyObject sadece sınıfları cast etmek için kullanılır. Dikkat edersek iki print arasındaki farkı görürüz. En bariz şekilde göreceğimiz fark stringlerin print oluş şekli. Any tipinde olan  dizideki stringi print ederken normal string gibi(iki tırnak arasında) print olurken, AnyObject tipinde olan dizideki string tırnaksız print olmuştur. Bunun sebebi ise AnyObject’e cast etmek istediğimizde Swift programlama dilinde struct olan Int, String gibi tipler Objective-C programlama dilinde sınıf olan (referans tipi) NSString ve NSNumber’a çevrilir ve ilk söylediğimiz haliyle AnyObject sadece sınıfları cast etmek için kullanılır. Bizim AnyObject dizimizin içindeki tipler artık Objective-C dilinde sınıf olan (referans tipi olan) tiplere dönüştürülür.

Özet

Bu dersimizinde Swift Type Casting konusunu inceledik. Swift programlama dilinde bir nesnenin tipini nasıl kontrol ederiz ve bir tipi farklı bir tip gibi davranmaya nasıl zorlarız bunu anlattık. Yaygın olarak kullanılan bu işlemin detaylı olarak bilinmesi geliştiriciler olarak bizi bir adım ileriye taşıyacaktır.  Dersi burada bitirirken herkese faydalı olmasını umarak, mutluluklar diliyorum. Soru, görüş ve önerilerinizi yorum kısmından veya soru-cevap kısmından iletebilirsiniz. Sağlıcakla…

Tüm Swift derslerimiz için tıklayınız.

Kaynak: https://docs.swift.org/swift-book/LanguageGuide/TypeCasting.html

28

Ali Hasanoglu

Yorum Yaz

Haftalık Bülten

Mobilhanem'de yayınlanan dersleri haftalık mail almak ister misiniz?