Swift Extensions Nedir? Swift Extensions Örnekleri

Merhaba arkadaşlar, Swift dersleri serimize Swift Extensions (Eklentiler) ile devam ediyoruz. Extensions var olan classlara, structlara, enumlara ve protokollere yeni işlevler ekleyebilmemize olanak verir ve yazdığımız kodu daha anlaşılır hale getirir. Extensionları iki farklı tipte inceleyeceğiz. Bir tanesi classları parçalayabilmemizi sağlayan özellikleri, bir diğeri ise Swift componentlerine metotlar ekleyerek bu metotlara proje içinde herhangi bir yerden erişmemizi sağlayan özelliği. Başlamadan önce Swift Inheritance yazısını okumanın faydalı olacağını söylemek isterim.

Swift Extensions Syntax

Extensions yazarken “extension” anahtar kelimesini kullanırız. Örnek üzerinden gidelim:

örn: 1
extension class { 

}

örn:2
extension class: protocol {
       
}

“extension” parametresinden sonra extend edeceğimiz yapıyı belirtiriz. Yukarıdaki ilk örnek bir class’a extension yazıp class’ı genişletmek için örneğin yeni init methodları, yeni methodlar ve parametreler tanımalamak için,  ikinci örnek ise class a bir protocol ü implement etmek için kullanılır.

Extensions bir yapıya generic bir metot veya özellik eklemek istediğimizde çok kullanışlı olmaktadır. Örnek vermek gerekirse:

extension Int{
   var kurus: Int {
   return self * 100
   }
}

 Yukarıdaki örnekte Int için yazdığımız bir extension bulunmaktadır. Bu extension sayesinde int bir para değerinin kaç kuruş olduğunu öğrenebiliriz. Büyük bir projede çalıştığımızı var sayalım ve para birimlerini kuruşa çevirmemiz gereken durumlar var. Eğer yukarıdaki gibi bir extension yazar isek bir int değeri ile kurus özelliğini çağırabiliriz.

let kurusDegeri = 5.kurus
print(kurusDegeri) // 500

Extension yazmadığımız durumda ise her seferinde değeri yüz ile çarpmamız gerekmektedir. Burada yaptığımız işlem basit bir matematiksel işlem ancak, örneğin 10 satır koddan oluşan bir fonksiyon olduğunu düşünelim; bu fonksiyonu farklı classlarda çağırabilmek için her classın içine bu fonksiyonu eklememiz gerekmektedir. Ancak int extension yazdığımızda proje içerisinde herhangi bir classtan erişebiliriz. Bir defa yazıp her yerde kullanabiliriz.

Swift Extensions ile neler yapabiliriz?

  • Extensions içine computed property ekleyebiliriz.
extension Int{
   var kurus: Int {
   return self * 100
   }
}

Ekelediğimiz computed propertyler sayesinde eklediğimiz sınıfın nesneleri vasıtasıyla bu propertylere erişebiliriz.

  • Extensions içine metot ekleyebiliriz.
extension Int{
   var kurus: Int {
   return self * 100
   }
         
   func birlerBasamagiBas() -> Int{
       return self % 10
   }
}

print(3242.birlerBasamagiBas()) // "2"

Int için yazdığımız extension içine bir adet de metot ekledik ve bu metot da int değerimizin birler basamağındaki sayıyı döndürüyor.

  • Extensions içine yapıya ait yeni bir veya birden fazla init() metodu yazabiliriz.
struct Car {
   var power: Int = 0
   var speed: Int = 0
}

extension Car{
         
    init(dict: NSDictionary) {
             
    }
         
    init(array: [Car]) {
             
    }
}

 

extension Car{
         
   init(dict: NSDictionary) {
             
   }
         
   init(array: [Car]) {
             
   }
         
   static subscript(power: Int) -> String{
      switch power{
                 
       case 1200:
           return "Yıllık sigorta ücreti 861 TL"
       case 1400:
           return "Yıllık sigorta ücreti 1.499 TL"
       case 1800:
           return "Yıllık sigorta ücreti 2.647 TL"
       case 2000:
           return "Yıllık sigorta ücreti 4.170 TL"
       default:
           return ""
         }
     }
}

print(Car[1400]) // "Yıllık sigorta ücreti 1.499 TL"
  • Extensions ile bir yapıya protokoller ekleyebiliriz.
protocol CarProtocol {
   mutating func speedUp(speedUp: Int)
}
      
extension Car: CarProtocol{
   mutating func speedUp(speedUp: Int) {
      self.speed += speedUp
   }
}
  • extension kullanarak kodu bir veya birden fazla parçaya  ayırabiliriz ve bu parçaladığımız classın, structın vb.  yapısında herhangi bir değişikliğe sebep olmaz.
// MARK: - first extension
extension CarViewController{
     //CarViewControllera ait metotlar bu alana yazılabilir.
}
     
// MARK: - second extension
extension CarViewController{
     //CarViewControllera ait metotlar bu alana yazılabilir.
}

Kodu parçalayarak okunurluğunu artırabiliriz. Özellikle bir classımızın kod satır sayısı çok fazla ise birbiriyle bağlantılı metotları aynı extension içine alıp kodu bir kaç defa bölmek kodun anlaşılırlığını artıracaktır. Aşağıda parçaladığım bir class örneği bulunmaktadır.

Yukarıda class gövdesi haricinde iki adet extension ile classı böldük çünkü class gövdesi artmaya başlasa bile artık ben tableview ve protokol metotlarımı ayrı bir alanda tutuyorum istediğim zaman rahatlıkla bunlara erişebilirim. Bu şekilde classın gövdesinden birbiriyle alakalı olan metotları extensionlar içinde toplamış olduk.

Örnek Extensions Kullanım Şekilleri

1- Swift componentlerine fonksiyonlar ekleyerek aynı işi yapan fonksiyonları tek bir yerden yönetmiş oluruz.

extension Int {
    
    func kareAl() -> Int{
        print(self)    // Konsol çıktısı -> 5
        return self * self
    }
}

let temp = 5.kareAl()
print(temp)   // Konsol çıktısı -> 25

Yukarıda Int değerler için bir extension ekledik. Bu extension  kareAl() adında bir metot bulunduruyor. Bu metot gelen int değerin karesini geri döndürüyor. Bu fonksiyonu istediğimiz int değer için projenin herhangi bir yerinden çağırabilmemiz bize çok kolaylık sağlamaktadır. Şimdi farklı bir metot daha yazalım:

extension Int {
    
    func kareAl() -> Int{
        print(self)
        return self * self
    }
    
    func topla(_ ikinciDeger: Int) -> Int{
        return self + ikinciDeger
    }
}

let temp2 = 7.topla(8)
print(temp2)  // 15

topla() metodumuz iki int değeri toplayan bir metoddur. Dikkat ettiyseniz metodu çağırdığımız parametreleri “self” değeri olarak okuyoruz. kareAl() metodunda self değerimiz 5 idi topla() metodunda ise metodu 7 ile çağırdığımız için self değerimiz 7 oldu. Bu metodlara çıkarma, bölme ve çarpma işlemlerini ekleyerek 4 işlemi yapan metodları barındıran bir int extension yapıp, projeniz içerisinde bu metodları rahatlıkla kullanabilirsiniz.

extension String{
    
    func stringConcat(_ param: String) -> String{
        return self + param
    }  
}
let str = "mer".stringConcat("haba")
print(str)  //  Konsol çıktısı -> merhaba

İki string değeri birbirine ekleyen stringConcat() metodu ve nasıl çağrıldığını yukarıda görebiliriz.

extension Array{
    
    func toplamiBul() ->Int{
        var toplam: Int = 0
        for item in self{
            let intItem = item as? Int ?? 0
            toplam += intItem
        }
        return toplam
    }
    
}

let arr: [Any] = [1,2,"Ali",3,4,5,6,7,"Veli"]
print(arr.toplamiBul())      // 28

içinde farklı tipten elemanlar olanın bir dizinin int değerlerinin toplamını toplamiBul() metodu vasıtasıyla bulabiliriz.  Arrayimizin elemanlarının tipi belli olmadığı için her seferinde yeni gelen elemanın int olup olmadığını( “let intItem = item as? Int ?? 0 “)kontrol etmeliyiz. Eğer elemanımız int değilse 0 elemanımızın değeri 0 olsun dedik.

2- TableView, collectionView vb. yapıların delegate, datasource vb fonksiyonlarını extension ile classtan ayrılabilir.

class CarViewController: UIViewController{
     
   override func viewDidLoad() {
   super.viewDidLoad()
    
   }
}
     
    
extension CarViewController: UITableViewDelegate, UITableViewDataSource {
         
        
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
             
     return 1
}
         
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

     return UITableViewCell()
}
         
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
     return 60
   }
}

3- iOS proje içindeki UIKit componentlerine extension yazılabilir. Özellikle  UIButton, UIView vb componentlerin proje içinde çok fazla kullanılabilecek bazı özellikleri için  yazılabilir.

extension UIView {
     
@IBInspectable var cornerRadius: CGFloat {
   get {
      return self.layer.cornerRadius
    }
   set {
      self.layer.cornerRadius = newValue
    }
  }
}

@IBInspectable parametresi, UIView için yazdığımız extension içindeki cornerRadius (view’ın köşelerini yuvarlak yapar) parametresini storyboard içinde değiştirebilmemizi sağlar. Storyboard ile tasarım yaparken bir view veya viewdan türemiş bir componente (UILabel, UIButton vb.) tıkladığımızda storyboard attributes inspector içinde cornerRadius özelliğini göreceğiz.  Bir proje içinde çok fazla kullanılabilecek bir özellik olan cornerRadius özelliğini UIView extension ile artık çok rahat bir şekilde ayarlayabilmekteyiz.

Yazdığımız bu extensionlar sayesinde işimiz bir hayli kolaylaşmaktadır. Tek bir defa yazıp sınırsız kullanabiliyor olmamız extensionların ne kadar güçlü ve önemli olduğunu bize göstermektedir.

Özet

Bu dersimizde Swift Extensions konusunu inceledik. Extensionlar sayesinde projeler daha anlaşılır hale getirilebilir. Bir defa yazıp her yerde kullanabileceğimiz için kod tasarrufu yapmış oluruz. Yukarıda bazı temel örnekleri verdik bunları artırmak ve çeşitlendirmek geliştiricinin ihtiyaçlarına göre değişir. Projelerimiz ne kadar büyürse büyüsün extensionlar vasıtasıyla birbiriyle alakalı metotları bir arada tutarak classlarımızı anlamlı parçalara da bölmüş oluruz. Çalışma şekli değişmeyecek ve daha anlaşılır hale gelecektir. 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/Extensions.html

21

Ali Hasanoglu

4 Yorum

  • selam hocam ben init(array: [Car]) kısmını anlamadım burda nasıl bir işlem yapıyoruz? extensionlara subscripts ekleme bölümünü biraz daha detaylı anlatır mısınız? teşekkürler.

    • Merhaba Onur, bir class’ı, struct’ı vb. initialize edebilmek için `init` fonksiyonuna ihtiyaç duyarız. Bu init fonksiyonu ile bir nesne oluşturup, bu nesne içindeki instance property ve instance metodlara erişim sağlayabiliriz. Bir struct için istediğimiz kadar init fonksiyonu ekleyebiliriz ve bahsettiğin `init(array: [Car])` kısmında dikkat çekmek istediğimiz nokta bu init fonksiyonunu struct’ın extension’ı içine de yazabiliyor olmamız. Öte yandan örnekteki hali ile bir Car listesi ile initialize etmemiz bir anlam ifade etmiyor, dediğim gibi buradaki değinmek istediğimiz nokta extension içine init fonksiyonu yazabiliyor olmamız. İkinci soru için ise şöyle bir cevap verebilirim, detaylı bir subscript anlatımı yapmıştım, oradan takip etmeni öneririm hala kafanda soru işareti olursa anlamadığın nokta ile ilgili yorum yazarsan ona da cevap vermeye çalışırım.

      • Merhabalar, benim asıl sormak istediğim. car struct’ını extension genişlettik ama extension içindeki subscriptte get yapmadık. yani print(Car[1400]) kısmında subscript 1400’ü nasıl algılıyor? ve init ederken neden array: [Car] yaptık neden int yapmadık. teşekkürler.

        • Merhaba Onur, subscript’te get yapıyoruz aslında, detaylarına buradan bakabilirsin. İkinci soruna cevaben de aşağıda da yazdığım üzere birden fazla init yazabildiğimizin örneğini verdik sadece, istersen bir integer alan init fonksiyonu da yazabilirsin, bu bağlamda sınır yok, sadece extension içinde bunu yapabiliyor olduğumuzu gösterdik.

Haftalık Bülten

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