Swift Properties

Merhaba arkadaşlar ,
mobilhanem.com sitemiz için anlattığımız/yayınladığımız Swift Dersleri serimize bu yazımızda Swift Properties ile devam edeceğiz. Bir önceki yazımızda Swift Enumeration Kullanımı  konusundan bahsetmiştik. Bu derse başlamadan önce xcode’u kurmak ve playground  üzerinde swift kodu yazabilmek için bu dersimizi okumanızı tavsiye ederim.

Stored Properties

Stored Property, bir sınıf veya structure instance ‘ında bulunan değişkenler veya sabitlerdirStored Propertyclass ‘lar ve structure ‘lar (struct) tarafından desteklenir. Uygulamamız içerisinde kullanıcının bilgilerini kullanabileceğimiz bir struct oluşturalım. Bu struct ‘ımızın iki adet property ‘si olsun. Bunlardan biri isim diğeride yas olsun.

struct KullaniciBilgileri {
    let isim: String
    var yas: Int
}

Struct ‘ımızın ismini KullaniciBilgileri olarak belirledik ve içerisine iki adet property ekledik. Bunlardan biri let keyword ‘ü ile tanımlanmış isim ‘dir. Yani sabit ve değiştirilemezdir. Diğeri ise var keyword ‘ü ile tanımlanmış yas ‘tır. Bu property ise var ile tanımlandığı için değiştirilebilirdir. Şimdi ise bu struct ‘ımızdan bir instance türetelim,

var birinciKullanici = KullaniciBilgileri(isim: "Taha", yas: 25)

birinciKullanici instance ‘ı var ile tanımlanmıştır. KullaniciBilgileri struct ‘ımızda isim property ‘si let ile tanımlandığı için yani sabit olarak tanımlandığı için birinciKullanici instance ‘ının isim property ‘sini değiştiremeyiz. yas property ‘si ise var ile tanımlandığı için değiştirilebilirdir. Hemen ilk tanımladığımız 25 değerini değiştirelim. Bu işlemi yapmadan önce birinciKullanici instance ‘ının yas property ‘sinin değerini ekrana bastıralım ve ardından değerini değiştirelim ve tekrar ekrana bastıralım ve farkını görelim,

print(birinciKullanici.yas)

Konsolda 25 çıktısını gördük. Şimdide değerini nasıl değiştirebildiğimizi görelim,

birinciKullanici.yas = 26

Yukarıda ki gibi instance ‘ımızın adını yazıp hangi property ‘sini değiştirmek istiyorsak onu belirtiyoruz ve ardından istediğimiz değeri atıyoruz. yas property ‘si Int türünde olduğundan dolayı sadece Int değerler verebilmekteyiz. Int dışında bir değer verirsek örneğin Double, Character gibi hata ile karşılaşırız. Şimdide birinciKullanici instance ‘ımızın yas property ‘sini değiştirebilmiş miyiz diye görmek için önceden yaptığımız gibi konsola bastıralım.

print(birinciKullanici.yas)

Ve konsolda 26 değerini gördük. Bu işlemi iki sayede gerçekleştirebildik birincisi KullaniciBilgileri struct ‘ımızda yazdığımız yas property ‘si var ile tanımlandığı için ve o struct ‘ımızdan oluşturduğumuz instance ‘ımızın (birinciKullanici) yine var ile tanımlandığı için.

Stored Properties of Constant Structure Instances

Baya havalı bir başlık oldu 🙂 Ama yukarıda yaptığımız örnek ile tek bir farkı vardır. Bu da struct ‘ımızdan oluşturduğumuz instance ‘ın, constant yani sabit olmasıdır. Constant olarak oluşturduğumuz instance ‘ımızın property ‘lerini değiştirememekteyiz. Eğer değiştirmeye çalışırsak hata ile karşılaşırız. Struct ‘ımızda ki property ‘lerimiz constant olmasa bile yani var ile tanımlanmış olsalar dahi instance ‘ımız constant olduğu için property ‘lerini değiştirememekteyiz hemen bir örnek üzerinde görelim,

let ikinciKullanici = KullaniciBilgileri(isim: "Dijkstra", yas: 45)

Constant olarak ikinciKullanici instance ‘ımızı oluşturduk. Bu örneğimizde de aynı struct ‘ımızı kullanıyoruz. Hemen var ile tanımlanmış olan yas property ‘isinin değerini değiştirmeye çalışalım,

ikinciKullanici.yas = 46

Yukarıda ki gibi ikinciKullanici instance ‘ımızın yas property ‘sini değiştirmeye çalıştığımızda derleyicimiz bize ikinciKullanici instance ‘ının let değilde var olarak tanımlamamızı önermektedir. Çünkü constant olarak yani let keyword ‘ü ile tanımlanan değişkenlerin değeri sonradan değiştirilemez, değiştirilmeye çalıştığında hata ile karşılaşırız.

Bu işlem class ‘lar için geçerli değildir. Class ‘lar references type ‘lar dır. Her hangi bir class ‘tan türettiğimiz instance ‘ımız constant olsa bile property değerini değiştirebilmekteyiz.

Lazy Stored Properties

Lazy  yani tembel stored propertyler, ilk değerleri kullanıcakları an gelene kadar başlangıç değeri hesaplanmayan property ‘lerdir. Tanımlamak için başlarına lazy keyword ‘ü yazılarak tanımlanırlar. Her zaman var keyword ‘ü ile tanımlanmak zorundadırlar. Bunun sebebi ise constant değerler initialization işleminden önce her zaman bir değere sahip olmak zorundadırlar bu durum da lazy olarak tanımlanmalarına engeldir. Hemen bir örnek üzerinde inceleyelim,

struct KullaniciBilgileri {
    
    var isim:String
    var yas:Int
    
    init(isim:String,yas:Int) {
        
        print("initalize")
        
        self.isim = isim
        self.yas = yas
        
    }
}

KullaniciBilgileri isimli struct ‘ımızı oluşturduk. Bu struct ‘ımıza birde init methodu ekledik. Ve bu methodumuzun içerisinde konsola print komutu ile “initalize” yazısını bastırdık.

struct Kullanici {
    
     var birinciKullanici = KullaniciBilgileri(isim: "Taha", yas: 25)
    
}

Kullanici adında bir başka struct ‘ımızı oluşturduk. Ve bu struct ‘ımız içerisinde KullaniciBilgileri struct ‘ımıza ait bir instance oluşturduk. Bu instance ‘ımız lazy olarak tanımlanmamıştır.

var kullanici = Kullanici()

Burada ise Kullanıcı struct ‘ımızın instance ‘ını oluşturduk. Önemli olan nokta birinciKullanici instance ‘ımızı çağırmamış olmamız. Buna rağmen konsolda init methodumuzda yazdığımız “initalize” yazısını konsolda görmüş olmamızdır. Buda init methodunun çağrıldığını göstermektedir. Şimdi ise lazy kullanmanın farkını görmek için Kullanici struct ‘ımıza ikinci bir instance ekleyelim,

Kullanici struct ‘ımız aşağıdaki şekildeki gibi olacaktır,

struct Kullanici {
    
//      var birinciKullanici = KullaniciBilgileri(isim: "Taha", yas: 25)
        lazy var ikinciKullanici = KullaniciBilgileri(isim: "Dijkstra", yas: 45)
}

ikinciKullanici isimli instance ‘ımız lazy olarak tanımlandı. Şimdide Kullanici struct ‘ımıza ait bir instance oluşturalım. Yukarıda yaptığımız işlemin aynısı olacaktır.

var kullanici = Kullanici()

Ve bu satır çalıştırıldıktan sonra konsolda “initalize” yazısını görmemiş olduk. Buda  KullaniciBilgileri isimli struct ‘ımızın içerisinde bulunan init methodunun çalışmadığını göstermektedir. Lazy ile tanımlanmış instance ‘ımız ilk başta verdiğim tanıma uygun olarak çalışmıştır. Ve daha çağırılmamıştır buda lazy keyword ‘ü ile sağlanmıştır. Şimdi de ikinciKullanici instance ‘ımızı kullanalım ve init methodumuzun çağırılıp çağrılmadığını görelim. Yukarıdaki anlattığıma göre çağırıldığı anda initalize işleminin gerçekleşmesi gerekmektedir ve bu işlem gerçekleşincede konsola gerçekleştiğini görmemiz için “initalize” yazısını bastıracaktır.

kullanici.ikinciKullanici

Ve lazy ile tanımlanmış olan ikinciKullanici instance ‘ımızı çağırdık ve ardından konsolda “initalize” yazısını gördük. var keyword ‘ü ile tanımladığımız için daha önceden yaptığımız gibi ikinciKullanici instance ‘ımızın isim veya yas property ‘sini aşağıda ki gibi değiştirebiliriz,

kullanici.ikinciKullanici.yas = 46

Ve ikinciKullanici instance ‘ımızın yas property ‘sini değiştirmiş olduk. Eğer kullanıcı.ikinciKullanici komutunu comment lerseniz (// ile) ekranda yine “initalize” yazısını görürsünüz. Çünkü instance ‘ımızı kullanmış olduk ve bundan dolayıda init methodumuz çalışmış oldu.

Computed Properties

Türkçe karşılığı olarak hesaplanmış özellik olarak geçen Computed Propertyler sınıflar, struct ve enumlar tarafından desteklenmektedir. Bu propertyler bir değer tutmaz, gerektiği zaman getter ve setter(opsiyonel) ile değerleri diğer propertylerden alarak yada değerleri diğer propertylere kaydederek yönetir.

class Zaman {
    var saniye:Double = 0
    
    init(saniye: Double) {
        self.saniye = saniye
    }
    
    var dakika: Double {
        get {
            return (saniye / 60)
        }
        set {
            self.saniye = (newValue * 60)
        }
    }
    
    var saat: Double {
        get {
            return (saniye / (60 * 60))
        }
        set {
            self.saniye = (newValue * (60 * 60))
        }
    }
    
    var gun:  Double {
        get {
            return (saniye / (60 * 60 * 24))
        }
        set {
            self.saniye = (newValue * (60 * 60 * 24))
        }
    }
}

Zaman isimli bir class yazdık. Ve bu class ‘ımızda saniyeyi güne, saate ve dakikaya çeviriyoruz. Yukarıda gördüğünüz newValue yazan yerler set methodu kullanılırsa şayet oraya gelen yeni değeri temsil etmektedir. Yukarıda ki gösterim yerine aşağıdaki gibi bir gösterimde kullanabilirsiniz,

    var gun:  Double {
        get {
            return (saniye / (60 * 60 * 24))
        }
        set(yeniGelenGunDegeri) {
            self.saniye = (yeniGelenGunDegeri * (60 * 60 * 24))
        }
    }

Evet şimdi yazdığımız class ‘tan bir örnek türetelim,

var yeniZaman = Zaman(saniye: 123.2)

Şeklinde oluşturduk,

yeniZaman.gun
yeniZaman.saat
yeniZaman.dakika
yeniZaman.saniye

Şeklinde yazdığımızda ise 123.2 saniyenin kaç gün, kaç saat, kaç dakika ve kaç saniye olduğunu playground üzerinde görebilmekteyiz. Burada yaptığımız işlem, değerleri okumaktı yani get methodu çalıştırılmış oldu. Ve değerleri bize hesaplayıp döndürmüş oldu. Kısaca değer okumuş olduk.

Şimdi de set methodumuzu çağırıcak işlemlerimizi yapalım. Bu işlemle birlikte çağırdığımız property ‘nin değerini değiştireceğiz,

yeniZaman.saat = 2.3

saat ‘in değerini değiştirerek set methodunun çalışmasını sağladık. Ve saat değerini 2.3 olarak set etmiş olduk. Ve yukarıdaki gibi gun, saat, dakika, saniye değerlerini tekrar görmek istersek değerlerinin tekrar hesaplandığını göreceğiz. Kısaca saat değerini tekrar belirlemiş olduk ve buna bağlı olarak diğer değerler tekrar hesaplandı ve get methodları çalıştırılmış oldu(Aşağıdaki işlemleri yaptıktan sonra) 

yeniZaman.gun
yeniZaman.saat
yeniZaman.dakika
yeniZaman.saniye

Ve değerlerimizi okuduk yani get methodu çağrılmış oldu. Get ve Set içerisine ekrana bir şeyler yazarak ne zaman get ne zaman set methodunun çağırıldığınıda görebilirsiniz.

Read-Only Computed Properties

Burada ise sadece değer okuyabileceğiz. Değeri set edemeyeceğiz yani değiştiremeyeceğiz. Daha iyi anlaşılması açısından yukarıdaki örnek için üzerinde açıklayacağım.

Yukarıdaki örneğimizde saat değerimizi 2.3 olarak sonradan set etmiştik. Read-Only de ise set işlemini gerçekleştirememekteyiz. Yani set methodumuz bulunmamaktadır,

    var saat: Double {
        get {
            return (saniye / (60 * 60))
        }
    }

Şeklinde yenileyebiliriz kodumuzu. Böylelikle,

yeniZaman.saat = 2.3

Satırı çalıştırıldığında hata ile karşılaşırız çünkü değeri sadece okuyabilmekteyiz değeri değiştirememekteyiz.

Property Observers

Türkçe karşılığı özellik gözlemleyicileridir. Property ‘lerin değerini sürekli gözlemler ve gözlemlediği değer değiştiği anda tetiklenirler yani çalışırlar. 2 adet property observers bulunmaktadır.

  • willset : Değer kaydedilmeden hemen önce çalışırlar.
  • didset : Yeni değer kaydedildikten hemen sonra çalışırlar.

Evet şimdi bu iki observer ‘ımızı örnek üzerinde inceleyelim,

class AdimSayar {
    var toplamAdim: Int = 0 {
        willSet(yeniToplamAdim) {
            print("Toplam adım sayısı \(yeniToplamAdim) olacak")
        }
        didSet {
            if toplamAdim > oldValue {
                print("Eklenen adım sayısı \(toplamAdim - oldValue)")
            }
        }
    }
}

AdimSayar isimli class ‘ımızı oluşturduk. Bu class ‘ımızda bir adet property ‘imiz mevcut. willSet observer ‘ımızın yanına bir değişkenimiz mevcut bu değişkenin ismini biz kendimiz belirliyoruz. Bu değişkenin değeri toplamAdim değişkeninin değeri değiştirilirken gelen yeni gelen değer olacaktır. didSet observer ‘ımızda ise böyle bir değişken bulunmamaktadır. Bunun yerine oldValue isimli bir değişkenimiz mevcuttur yeni bir parametre vermez isek default olarak oldValue isimli parametreyide yukarıdaki gibi kullanabilmekteyiz. didSet observer ‘ımız toplamAdim property ‘sinin değeri değiştirildikten sonra çalışmaktadır. Burada yaptığımız işlem ise toplamAdim sayısının  ne kadar olacağını görmek ve her seferinde adim sayisinin ne kadar arttığını görmektir. willSet observer ‘ımızda ise bu default parametremizin adı newValue ‘dur.

let adimSayar = AdimSayar()
adimSayar.toplamAdim = 100

Yukarıdaki işlemi anlatmadan önce dikkatinizi çekmek istediğim bir durum var. Burada AdimSayar sınıfından oluşturduğumuz adimSayar isimli instance ‘ımız let(constant olarak) ile tanımlanmış olmasına rağmen toplamAdim isimli property ‘sini değiştirebildik. Bu durumu yukarıda Stored Properties of Constant Structure Instances başlığı altında bahsetmiştim.

adimSayar instance ‘ımızın toplamAdim property’sini 100 olarak belirledik. toplamAdim ‘nın değeri değişmeden önce willSet observer ‘ımız çalışacaktır. Böylelikle ekrana “Toplam adım sayısı 100 olacak” yazısını bastıracaktır. toplamAdim property ‘sinin değeri değiştikten sonra ise didSet observer ‘ımız çalışacaktır ve ekrana “Eklenen adım sayısı 100” yazısını bastıracaktır. toplamAdim property ‘sinden default parametre olarak kullandığımız oldValue değerini çıkartarak aradaki farkı bulmaktayız. oldValue değerimiz her zaman bir önceki toplamAdim değerimiz olacaktır. Özet olarak willSet değer değiştirilmeden önce çalıştırılır ve olacak değeri newValue ile görebiliriz. didSet ise değer değiştikten sonra çalıştırılır ve önceki değeri oldValue ile görebiliriz. Şimdi sizde

adimSayar.toplamAdim = 200

yazarak neler olduğunu görebilirsiniz.

 

Ve Swift Properties dersimizin sonuna geldik. Kafanıza takılanlar için yorum kısmından yorum yazabilirsiniz 🙂

print(“Simplicity is prerequisite for reliability.”)

print(“Edsger Dijkstra”)

 

 

58

Taha Eren Buyruk

Başkent Üniversitesi Bilgisayar Mühendisliği.

Yorum Yaz

Haftalık Bülten

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