Swift Subscripts Yapısı

Merhaba arkadaşlar, Swift dersleri serimize  Swift Subscripts yapısından ve nasıl kullanıldığından bahsederek devam edeceğiz. Bu yapının avantajları neler ve hangi durumlarda bu yapıyı kullanmalıyız gibi soruların yanıtlarını vereceğiz.

Swift Subscripts nedir?

Swift Subscript yapısı classlar, structlar ve enumlar içerisine tanımlanabilir. Bu yapılar içerisinde yer alan diziler, kümeler, collectionlar vb. yapıların değerlerini okumayı(get) ve değiştirebilmeyi(set) mümkün kılar. Herhangi bir metod tanımlamaya ihtiyaç duymadan değerleri getirebildiğimiz ve değiştirebildiğimiz için bazı durumlarda işimizi kolaylaştıracaktır.

Bir tip içine birden fazla subscript tanımlanabilir ve subscript içine birden fazla parametre alabilir. Subscript yapısının nasıl kullanıldığını örnekte görelim:

 subscript(index: Int) -> String{
        get {
            
            return String()
        }
        set (newValue) {
        
        }
    }

Not 1: Swift Subscripts içindeki set() metodu opsiyoneldir ancak get() metodunu yazmak zorundayız.

Eğer set() metodunu kullanmayacaksak get() metod ismini ve parantezlerini silebiliriz. Nasıl?

  subscript(index: Int) -> Int{
     // bu alana geri döndürmek istediğiniz değeri yazabilirsiniz.
     return Int()
  }

Array ve Dictionary Yapılarında Subscript

Array ve dictionary yapıları arka planda subscript yapısını kullanmaktadır. Şu kısımdan array ve dictionary yapılarının elementlerine erişebileceğimiz metodlar(Accessing elements) içerisinde subscript metodu görülebilmektedir. Bir dizinin herhangi bir elemanına erişmek istediğimizde oluşturduğumuz dizinin indisi vasıtasıyla istediğimiz değere erişebiliriz. Aslında Array içinde bulunan subscript metoduna dizinin indisini göndermiş oluruz ve karşılığında bize dizinin o indisteki değeri subscript içerisinde bulunan get() metodu vasıtasıyla döndürülür. Aynı şekilde bir dizinin belirli bir indisine değer atamasını subscript içinde bulunan set() metodu vasıtasıyla yapabiliriz. Ayrıca Xcode ile Array’in metodlarına erişerek (command tuşuna basılı tutarak Array classının üzerine tıklamalıyız), Array içerisinde bulunan subscript metodunu bulabilmekteyiz.

Yukarıdaki subscript metodu aşağıdaki şekilde gerçeklenmektedir. Array structından oluşturduğumuz nesneyi kullanarak bu subscript metoduna erişebiliriz ve belirli indisteki değeri okuyup, değiştirebiliriz.

struct Array<Element> {
    subscript(index: Int) -> Element{
       get{
          return ...
       }
       set(newValue){
  
       }
    }
}

Bir örnek vasıtasıyla Array yapısında bulunan subscriptin nasıl çalıştığını görelim.

var intArray: Array<Int> = [10,20,30,40,50,60]  // intArray nesnesi oluşturduk.
print("Sıfırıncı indis değeri = \(intArray[0])") // get metodu vasıtasıyla okuyoruz
intArray[0] = 100 // set metodu vasıtasıyla atama yapıyoruz.
print("Sıfırıncı indis değeri = \(intArray[0])") // get metodu vasıtasıyla okuyoruz

Konsol Çıktısı ->

Sıfırıncı indis değeri = 10

Sıfırıncı indis değeri = 100

Yazdığımız ilk print metodunda intArrayin sıfırıncı indisini subscript içinde bulunan get() metodu vasıtasıyla okuduk. Hemen arkasından intArray[0] = 100 işlemi ile sıfırıncı indise 100 değerini set() metodu vasıtasıyla atadık.  Buradaki Element tipi dönüş parametresinin generic bir tip olduğunu belirtir. Generics konusunu anlatırken bunu daha detaylı açıklayacağız ancak kısaca bahsetmek gerekirse bu Arrayin içine farklı tipleri alabildiğini gösterir. Yani bu bir Int array de olabilir, String array de olabilir vb.

Yukarıda Array içerisinde bulunan subscript yapısını açıkladık aynı yöntem dictionaryler için geçerlidir. Dictionaryler subscript metoduna “key” değeri olarak string beklemektedir. Karşılığında dönüş parametresini verirler. Bir örnek de dictionary için yapalım:

var dict: Dictionary = ["isim": "ALİ", "soyisim": "HASANOĞLU"]

if let name = dict["isim"], let surname = dict["soyisim"]{ // get() metodu vasıtasıyla okuma yaptık
   print("Benim adım \(name) \(surname)")
}

dict["isim"] = "ali" // set() metodu vasıtasıyla yeni değeri atadık.

if let name = dict["isim"], let surname = dict["soyisim"]{ // get() metodu vasıtasıyla okuma yaptık
   print("Benim adım \(name) \(surname)")
}

Konsol çıktısı    ->

Benim adım ALİ HASANOĞLU

Benim adım ali HASANOĞLU

Subscript yapısı Array ve Dictionarylerde benzer şekilde çalışmaktadır. Örneklerde de görüldüğü gibi indis veya key değeri vasıtasıyla bize dönüş değerlerini vermektedirler. Şimdi kendi subscriptlerimizi oluşturarak bu yapıyı kendi class, struct ve enumlarımızda nasıl kullanabileceğimize bakalım.

Custom Subscripts Oluşturma

Yukarıda subscripts yapısını açıkladık. Şimdi kendimiz bir struct tanımlayıp kendi subscriptimizi oluşturalım.

struct Event {
    
    var eventsArray: [String] = ["1. etkinlik","2. etkinlik","3. etkinlik","4. etkinlik","5. etkinlik"]
    
    subscript(eventIndex: Int) -> String{
        get{
            return eventsArray[eventIndex]
        }
        set(newValue){
            eventsArray[eventIndex] = newValue
        }
    }
}

Bir Event structı oluşturup içine bir custom subscript ekledik. Bu subscript sayesinde Eventten oluşturacağımız bir nesne vasıtasıyla eventsArray dizisinin değerlerini alabilir ve değiştirebiliriz(instance subscript).

var instance = Event()
print("İkinci indis değeri = \(instance[2])")
instance[2] = "3. oyun"
print("İkinci indis değeri = \(instance[2])")

Konsol çıktısı  ->

İkinci indis değeri = 3. etkinlik

İkinci indis değeri = 3. oyun

Bir tip içerisine birden fazla subscript tanımlanabileceğinden bahsetmiştik. Event structımızı şu şekilde güncelleyelim:

struct Event {
    
    var eventsArray: [String] = ["1. etkinlik","2. etkinlik","3. etkinlik","4. etkinlik","5. etkinlik"]
    
    subscript(eventIndex: Int) -> String{
        get{
            return eventsArray[eventIndex]
        }
        set(newValue){
            eventsArray[eventIndex] = newValue
        }
    }
    
    subscript(event: String) -> Int{
        return eventsArray.firstIndex(of: event)!
    }
}

İkinci bir subscript ekledik ve bu subscripten beklentimiz göndereceğimiz eventin isminin(String) ilk olarak kaçıncı indiste bulunduğunu geri döndürmesi olacaktır. Örneğe bakalım:

print("3. oyun ilk olarak \(instance["3. oyun"]). indiste geçmektedir.")

Konsol çıktısı  ->

3. oyun ilk olarak 2. indiste geçmektedir.

Swift Type Subscripts

Yukarıda oluşturduğumuz subscriptler instance subscriptir. Yani bir tip tanımlanır ve bu tipten oluşturulan nesneler vasıtasıyla subscripte erişilir. Yukarıda oluşturduğumuz Event structı bir tiptir. Bu tipten oluşturduğumuz instance nesnesi vasıtasıyla subscripte eriştik. Peki direkt olarak Event tipi ile subscripte erişmek mümkün müdür?

-Swift 5.1 ile gelen yeni özellik sayesinde  Type subscripts vasıtasıyla oluşturduğumuz tip ile subscriptlere erişmemiz mümkündür. İki çeşit type subscript vardır; static subscript ve class subscript.

Static Subscript ve Class Subscript Kullanımı

Static ve class subscriptler yukarıda da bahsettiğimiz gibi tanımladığımız tipler vasıtasıyla subscripte erişmemizi sağlar. Örnek vasıtasıyla açıklayalım:

@dynamicMemberLookup
class Greeting {
  let greeting: String

  init(greeting: String) {
    self.greeting = greeting
  }

  static subscript(greeting: String) -> String {
    switch greeting {
      case "Hi":
        return "Hi Professor Dumbledore"
      case "Hello":
        return "Hello Professor Snape"
      default:
        return "Hi Hagrid"
    }
  }

  class subscript(dynamicMember greeting: String) -> String {
    switch greeting {
      case "Hi":
        return "Hi Professor Dumbledore"
      case "Hello":
        return "Hello Professor Snape"
      default:
        return "Hi Hagrid"
    }
  }
}

static subscript class, struct ve enumlar ile birlikte kullanılabilir. class subscript ise sadece classlar için kullanılabilir. Eğer classlarda class subscript  kullanırsak subscripti oluşturduğumuz classın alt classlarında da bu subscripti override edebiliriz. @dynamicMemberLookup parametresi sayesinde tip sonuna nokta ekleyip sonrasında subscripte göndermek istediğimiz parametreyi veriyoruz. @dynamicMemberLookup parametresini kullanmaz isek  tipi yazdıktan sonra köşeli parantez içine subscript metodunun bizden istediği parametreyi vermemiz gerekir. @dynamicMemberLookup parametresini  yazdığımız ve yazmadığımız durumlar yukarıda görülmektedir ve hem class hem de static subscripte bu parametreyi kullanabiliriz. Örnekler daha açıklayıcı olacaktır:

print(Greeting["Hi"])
print(Greeting["Hello"])
print(Greeting["Howdy"])
        
print(Greeting.Hi)
print(Greeting.Hello)
print(Greeting.Howdy)

// Oluşturduğumuz Greeting tipi ile subscripte erişiyoruz!

Yazdığımız ilk üç adet print metodu içerisinde static subscript, ikinci üçlü grup içerisinde ise class subscript çağırdık. Ayrıca class subscriptimiz ile @dynamicMemberLookup kullandık. Bu parametreyi kullanabilmek için subscriptin bizden parametre olarak beklediği string değerin önüne “dynamicMember” parametresini eklememiz gerekir.

Konsol Çıktısı ->

Hi Professor Dumbledore

Hello Professor Snape

Hi Hagrid

Hi Professor Dumbledore

Hello Professor Snape

Hi Hagrid

Özet

Bu yazımızda Swift dilinde bulunan subscript yapısını inceledik. Array ve dictionary yapılarının arka planda subscript kullandığını gördük. Kendimiz bir subscripti nasıl oluştururuz buna baktık ve instance subscript, yani oluşturduğumuz tipten ürettiğimiz nesne ile ulaşılan subscript ve type subscriptten bahsettik. Type subscript, static subscript ve class subscript olmak üzere ikiye ayrılıyordu. Class subscriptler sadece class ile kullanılırken, instance subscriptler class, struct ve enum ile birlikte kullanılabiliyordu. Static subscriptler enumlar için get() ve set() metodu yazmadan değerlere erişmeye izin vermektedir. Bu bize enumları daha efektif kullanma imkanı sağlamaktadır. @dynamicMemberLookup parametresi sayesinde nesnelerin özelliklerine eriştiğimiz şekilde(nokta “.” kullanarak) subscripte parametre gönderme imkanına sahip oluyorduk.

Subscript yapısı tiplerin özelliklerine erişmek için bir kısayol vazifesi görmektedir. Metodlar vasıtasıyla da özelliklere erişilebilir ancak subscript kullanarak daha kısa yolla ve daha az kod yazarak bunu gerçekleştirebiliriz. Herkes için faydalı olmasını umarak yazımı burada tamamlıyorum. Sorunuz olduğunda yorum kısmında veya soru-cevap kısmında sorabilirsiniz. Mutluluklar dilerim, sağlıcakla kalınız…

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

5

Ali Hasanoglu

Yorum Yaz

Haftalık Bülten

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