Bir iOS Geliştirici Kılavuzu: Objective-C'den Learning Swift'e

Yayınlanan: 2022-03-11

2008'de Apple, iPhone SDK 2.0'ı duyurdu ve piyasaya sürdü. Bu olay, yazılım geliştirmede başka bir devrim başlattı ve yeni bir geliştirici türü doğdu. Artık iOS geliştiricileri olarak kabul ediliyorlar.

Bu geliştiricilerin çoğu daha önce Objective-C kullanmamıştı ve bu Apple'ın onlara attığı ilk zorluktu. Alışılmadık sözdizimine ve manuel bellek yönetimine rağmen, son derece başarılı oldu ve App Store'u on binlerce uygulamayla doldurmaya yardımcı oldu. Apple, her sürümde sürekli olarak Objective-C'yi geliştirdi, bloklar ve değişmez değerler ekledi, otomatik referans sayımı ile basitleştirilmiş bellek yönetimi ve modern bir programlama dilinin göstergesi olan diğer birçok özellik.

Ve 6 yıl boyunca Objective-C geliştirip çalıştıktan sonra Apple, geliştiricilere başka bir meydan okuma koymaya karar verdi. Bir kez daha iOS geliştiricilerinin yeni bir programlama dili öğrenmesi gerekecek: Swift . Swift, güvenli olmayan işaretçi yönetimini kaldırır ve hem Objective-C hem de C ile etkileşimi sürdürürken güçlü yeni özellikler sunar.

Swift 1.0 zaten istikrarlı ve güçlü bir geliştirme platformudur ve önümüzdeki yıllarda ilginç şekillerde gelişeceği kesindir. Açıkça iOS geliştirmenin geleceği olduğu için bu yeni dili keşfetmeye başlamak için mükemmel bir an.

Bu öğreticinin amacı, Objective-C geliştiricilerine yeni Swift dil özelliklerine hızlı bir genel bakış sunarak bir sonraki adımı atmanıza ve Swift'i günlük işlerinizde benimsemeye başlamanıza yardımcı olmaktır. Objective-C'yi açıklamak için çok fazla zaman harcamayacağım ve iOS geliştirmeye aşina olduğunuzu varsayacağım.

Swift, Objective-C iOS geliştiricileri için oyunu değiştirdi.

Swift ve Objective-C'yi denemek

Swift'i keşfetmeye başlamak için tek yapmanız gereken App Store'dan XCode'u indirmek ve deney yapmak için bir oyun alanı oluşturmak. Bu makalede bahsedilen tüm örnekler bu şekilde yapılmıştır.

Apple'ın Swift ana sayfası, Swift programlamayı öğrenmek için en iyi referanstır. Bunun paha biçilmez olduğunu göreceksiniz ve Swift geliştirme ile tamamen hızlanana kadar buraya sık sık geleceğinize inanıyorum.

Değişkenler ve Sabitler

Swift'de bir değişken bildirmek var anahtar sözcüğü kullanılarak yapılır.

 var x = 1 var s = "Hello"

İki değişken x ve s farklı türde olduğunu fark edeceksiniz. x bir Tamsayıdır, s ise bir Dizedir. Swift, güvenli bir tür dilidir ve atanan değerden değişken türleri çıkarır. Kodunuzu daha okunaklı hale getirmek istiyorsanız, isteğe bağlı olarak değişkenin türüne açıklama ekleyebilirsiniz:

 var y: Int y = 2

Sabitler benzerdir, ancak onları var yerine let kullanarak bildirirsiniz. Bir sabitin değerinin derleme zamanında bilinmesi gerekmez, ancak ona tam olarak bir kez bir değer atamanız gerekir.

 let c1 = 1 // Constant known at compile time var v = arc4random() let c2 = v // Constant known only at run time

Adlarından da anlaşılacağı gibi, bunlar değişmezdir, bu nedenle aşağıdaki kod bir derleme zamanı hatasına neden olur.

 let c = 1 c = 3 // error

Diğer türler de sabit olarak bildirilebilir. Örneğin, aşağıdaki kod bir diziyi sabit olarak bildirir ve herhangi bir öğeyi değiştirmeye çalışırsanız Swift derleyicisi bir hata bildirir:

 var arr2 = [4, 5, 6] arr2[0] = 8 print (arr2) // [8, 5, 6] let arr = [1, 2, 3] a[0] = 5 // error

Opsiyonel

Sabitler, bildirilirken başlatılmalı ve değişkenler kullanılmadan önce başlatılmalıdır. Peki Objective-C nil eşdeğeri nerede? Swift, isteğe bağlı değerleri tanıtır. İsteğe bağlı değerler bir değere sahip olabilir veya nil olabilir. Aşağıdaki koda bir göz atarsanız, x Optional bir 2014 değeri atandığını fark edeceksiniz. Bu, Swift derleyicisinin x de nil olabileceğinin farkında olduğu anlamına gelir.

 var s = "2014" var x = s.toInt() print(x) // Optional(2014)

Bu kodda bir değişiklik yaparsanız ve "abc" değerini bir Tamsayıya dönüştürülemeyen s atarsanız, x artık bir nil olduğunu fark edeceksiniz.

 var s = "abc" var x = s.toInt() print(x) // nil

toInt() işlevinin dönüş türü Int? , isteğe bağlı bir Int . x üzerinde standart bir fonksiyon çağırmaya çalışalım:

 var x = "2014".toInt() print(x.successor()) // error

x isteğe bağlı olduğundan ve potansiyel olarak nil olabileceğinden , derleyici bir hata sinyali verir. Önce x test etmeliyiz ve successor işlevin nil değerinde değil, gerçek bir sayı üzerinde çağrıldığından emin olmalıyız:

 var x = "2014".toInt() if x != nil { print(x!.successor()) // 2015 }

Bir ünlem işareti (!) ekleyerek x paketini açmamız gerektiğini unutmayın . x bir değer içerdiğinden emin olduğumuzda ona erişebiliriz. Aksi takdirde çalışma zamanı hatası alırız. İsteğe bağlı olanı isteğe bağlı olmayan bir değişkene dönüştürerek Swift'in isteğe bağlı bağlama dediği şeyi de yapabiliriz.

 let x = "123".toInt() if let y = x { print(y) }

if ifadesindeki kod, yalnızca x bir değeri varsa yürütülür ve onu y atar. y paketini açmamız gerekmediğine dikkat edin, x nil olmadığını bildiğimiz için type isteğe bağlı değildir.

İsteğe bağlı zincirleme gibi isteğe bağlı özellikler ve hoş özellikler hakkında daha fazla ayrıntı okumak için Apple'ın Swift eğitimine bakın

dize enterpolasyonu

Objective-C'de dizeleri biçimlendirme genellikle stringWithFormat: yöntemiyle yapılır:

 NSString *user = @"Gabriel"; int days = 3; NSString *s = [NSString stringWithFormat:@"posted by %@ (%d days ago)", user, days];

Swift'in aynısını yapmak için dize enterpolasyonu adı verilen bir özelliği vardır, ancak daha kompakt ve okunması daha kolaydır:

 let user = "Gabriel" let days = 3 let s = "posted by \(user) \(days) ago"

Ayrıca şu ifadeleri de kullanabilirsiniz:

 let width = 2 let height = 3 let s = "Area for square with sides \(width) and \(height) is \(width*height)"

Swift'in string enterpolasyonu ve diğer yeni özellikleri hakkında daha fazla bilgi edinmek için buraya gidin.

Fonksiyonlar

Swift'deki fonksiyon tanımı C'den farklıdır. Örnek bir fonksiyon tanımı aşağıdadır:

 func someFunction(s:String, i: Int) -> Bool { ... // code }

Swift işlevleri birinci sınıf türlerdir . Bu, değişkenlere işlevler atayabileceğiniz, bunları diğer işlevlere parametre olarak iletebileceğiniz veya tür döndürmelerini sağlayabileceğiniz anlamına gelir:

 func stringLength(s:String) -> Int { return countElements(s) } func stringValue(s:String) -> Int { if let x = s.toInt() { return x } return 0 } func doSomething(f:String -> Int, s:String) -> Int { return f(s).successor() } let f1 = stringLength let f2 = stringValue doSomething(f1, "123") // 4 doSomething(f2, "123") // 124

Yine Swift, f1 ve f2 ( String -> Int ) türlerini çıkarır, ancak bunları açıkça tanımlayabilirdik:

 let f1:String -> Int = stringLength

İşlevler ayrıca diğer işlevleri de döndürebilir:

 func compareGreaterThan(a: Int, b: Int) -> Bool { return a > b } func compareLessThan(a: Int, b: Int) -> Bool { return a < b } func comparator(greaterThan:Bool) -> (Int, Int) -> Bool { if greaterThan { return compareGreaterThan } else { return compareLessThan } } let f = comparator(true) println(f(5, 9))

Swift'deki işlevler için bir kılavuz burada bulunabilir.

numaralandırmalar

Swift'deki numaralandırmalar, Objective-C'dekinden çok daha güçlüdür. Swift yapıları olarak, yöntemlere sahip olabilirler ve değere göre iletilirler:

 enum MobileDevice : String { case iPhone = "iPhone", Andro, WP8 = "Windows Phone8", BB = "BlackBerry" func name() -> String { return self.toRaw() } } let m = MobileDevice.Android print(m.name()) // "Android"

Objective-C'den farklı olarak Swift numaralandırmaları, tamsayıların yanı sıra her üye için değer olarak Dizeler, karakterler veya kayan noktalar atayabilir. Uygun toRaw() yöntemi, her üyeye atanan değeri döndürür.

Numaralandırmalar ayrıca parametrelenebilir:

 enum Location { case Address(street:String, city:String) case LatLon(lat:Float, lon:Float) func description() -> String { switch self { case let .Address(street, city): return street + ", " + city case let .LatLon(lat, lon): return "(\(lat), \(lon))" } } } let loc1 = Location.Address(street: "2070 Fell St", city: "San Francisco") let loc2 = Location.LatLon(lat: 23.117, lon: 45.899) print(loc1.description()) // "2070 Fell St, San Francisco" print(loc2.description()) // "(23.117, 45.988)"

Numaralandırmalar hakkında daha fazla bilgiyi burada bulabilirsiniz.

demetler

Tuples, birden çok değeri tek bir bileşik değerde gruplandırır. Bir tanımlama grubu içindeki değerler herhangi bir türden olabilir ve birbirleriyle aynı türden olmaları gerekmez.

 let person = ("Gabriel", "Kirkpatrick") print(person.0) // Gabriel

Ayrı ayrı demet öğelerini de adlandırabilirsiniz:

 let person = (first: "Gabriel", last: "Kirkpatrick") print(person.first)

Tuple'lar, birden fazla değer döndürmesi gereken işlevler için dönüş türleri olarak son derece uygundur:

 func intDivision(a: Int, b: Int) -> (quotient: Int, remainder: Int) { return (a/b, a%b) } print(intDivision(11, 3)) // (3, 2) let result = intDivision(15, 4) print(result.remainder) // 3

Objective-C'den farklı olarak Swift, bir switch ifadesinde kalıp eşleştirmeyi destekler:

 let complex = (2.0, 1.1) // real and imaginary parts switch complex { case (0, 0): println("Number is zero") case (_, 0): println("Number is real") default: println("Number is imaginary") }

İkinci durumda, sayının gerçek kısmıyla ilgilenmiyoruz, bu yüzden herhangi bir şeyi eşleştirmek için bir _ kullanıyoruz. Her durumda ek koşulları da kontrol edebilirsiniz. Bunun için kalıp değerlerini sabitlere bağlamamız gerekiyor:

 let complex = (2.0, 1.1) switch complex { case (0, 0): println("Number is zero") case (let a, 0) where a > 0: println("Number is real and positive") case (let a, 0) where a < 0: println("Number is real and negative") case (0, let b) where b != 0: println("Number has only imaginary part") case let (a, b): println("Number is imaginary with distance \(a*a + b*b)") }

Yalnızca karşılaştırmada veya case ifadesinde kullanacağımız değerleri nasıl bağlamamız gerektiğine dikkat edin.

Tuple'lar hakkında daha fazla okumak için buraya gidin.

Sınıflar ve Yapılar

Objective-C'den farklı olarak Swift, özel sınıflar ve yapılar için ayrı arayüz ve uygulama dosyaları oluşturmanızı gerektirmez. Swift'i öğrendikçe, tek bir dosyada bir sınıf veya yapı tanımlamayı öğreneceksiniz ve bu sınıf veya yapının harici arayüzü otomatik olarak diğer kodların kullanması için hazır hale getirilecek.

Sınıfları Tanımlama

Sınıf tanımları çok basittir:

 class Bottle { var volume: Int = 1000 func description() -> String { return "This bottle has \(volume) ml" } } let b = Bottle() print(b.description())

Gördüğünüz gibi, beyan ve uygulama aynı dosyada . Swift artık başlık ve uygulama dosyalarını kullanmıyor. Örneğimize bir etiket ekleyelim:

 class Bottle { var volume: Int = 1000 var label:String func description() -> String { return "This bottle of \(label) has \(volume) ml" } }

Derleyici, etiket isteğe bağlı olmayan bir değişken olduğundan şikayet eder ve bir Bottle başlatıldığında bir değeri tutmaz. Bir başlatıcı eklememiz gerekiyor:

 class Bottle { var volume: Int = 1000 var label:String init(label:String) { self.label = label } func description() -> String { return "This bottle of \(label) has \(volume) ml" } }

Veya, başlatılmayacak bir özellik için Optional türü kullanabiliriz. Aşağıdaki örnekte, volume bir Optional Integer yaptık:

 class Bottle { var volume: Int? var label:String init(label:String) { self.label = label } func description() -> String { if self.volume != nil { return "This bottle of \(label) has \(volume!) ml" } else { return "A bootle of \(label)" } } }

Yapılar

Swift dilinde de structs vardır, ancak bunlar Objective-C'den çok daha esnektir. Aşağıdaki kod öğreticisi bir struct tanımlar:

 struct Seat { var row: Int var letter:String init (row: Int, letter:String) { self.row = row self.letter = letter } func description() -> String { return "\(row)-\(letter)" } }

Swift'deki sınıflar gibi, yapılar da yöntemlere, özelliklere, başlatıcılara sahip olabilir ve protokollere uygun olabilir. Sınıflar ve yapılar arasındaki temel fark, sınıfların referansa göre, yapıların ise değere göre iletilmesidir .

Bu örnek, referans yoluyla sınıfları geçmeyi gösterir:

 let b = Bottle() print(b.description()) // "b" bottle has 1000 ml var b2 = b b.volume = 750 print(b2.description()) // "b" and "b2" bottles have 750 ml

struct ile benzer bir durumu denersek, değişkenlerin değere göre iletildiğini fark edeceksiniz:

 var s1 = Seat(row: 14, letter:"A") var s2 = s1 s1.letter = "B" print(s1.description()) // 14-B print(s2.description()) // 14-A

Ne zaman struct ve ne zaman class kullanmalıyız? Objective-C ve C'de olduğu gibi, birkaç değeri gruplamanız gerektiğinde yapıları kullanın ve referans vermek yerine kopyalanmalarını bekleyin. Örneğin, karmaşık sayılar, 2B veya 3B noktalar veya RGB renkleri.

Bir sınıfın bir örneği, geleneksel olarak bir nesne olarak bilinir. Bununla birlikte, Swift sınıfları ve yapıları, işlevsellik açısından diğer dillere göre çok daha yakındır ve bir sınıf ya da yapı türünün örneklerine pek çok işlevsellik uygulanabilir. Bu nedenle, Swift başvurusunda kullanılan daha genel terim, bu ikisinden herhangi biri için geçerli olan instance .

Swift sınıflarının ve yapılarının temellerini buradan öğrenin.

Özellikleri

Daha önce gördüğümüz gibi, Swift'deki özellikler bir sınıf veya yapı tanımı içinde var anahtar sözcüğü ile bildirilir. Sabitleri bir let deyimi ile de bildirebiliriz.

 struct FixedPointNumber { var digits: Int let decimals: Int } var n = FixedPointNumber(digits: 12345, decimals: 2) n.digits = 4567 // ok n.decimals = 3 // error, decimals is a constant

Ayrıca, weak anahtar sözcüğüyle önek eklemediğiniz sürece, sınıf özelliklerine güçlü bir şekilde başvurulduğunu unutmayın. Ancak isteğe bağlı olmayan özelliklerin zayıf olduğu bazı incelikler vardır, bu nedenle Apple'ın Swift kılavuzundaki otomatik referans sayma bölümünü okuyun.

Hesaplanan Özellikler

Hesaplanan özellikler aslında bir değer saklamaz. Bunun yerine, diğer özellikleri ve değerleri dolaylı olarak almak ve ayarlamak için bir alıcı ve isteğe bağlı bir ayarlayıcı sağlarlar.

Aşağıdaki kod, hesaplanan değer sign bir örneğini sağlar:

 enum Sign { case Positive case Negative } struct SomeNumber { var number:Int var sign:Sign { get { if number < 0 { return Sign.Negative } else { return Sign.Positive } } set (newSign) { if (newSign == Sign.Negative) { self.number = -abs(self.number) } else { self.number = abs(self.number) } } } }

Yalnızca bir alıcı uygulayarak salt okunur özellikleri de tanımlayabiliriz:

 struct SomeNumber { var number:Int var isEven:Bool { get { return number % 2 == 0 } } }

Objective-C'de, özellikler genellikle derleyici tarafından açıkça veya otomatik olarak oluşturulan bir örnek değişken tarafından desteklenir. Öte yandan Swift'de, bir özelliğin karşılık gelen bir örnek değişkeni yoktur . Diğer bir deyişle, bir mülkün destek deposuna doğrudan erişilemez. Bunun Objective-C'de olduğunu varsayalım.

 // .h @interface OnlyInitialString : NSObject @property(strong) NSString *string; @end // .m @implementation OnlyInitialString - (void)setString:(NSString *newString) { if (newString.length > 0) { _string = [newString substringToIndex:1]; } else { _string = @""; } } @end

Swift'de hesaplanan özelliklerin bir destek deposu olmadığından, şöyle bir şey yapmamız gerekiyor:

 class OnlyInitialString { var initial:String = "" var string:String { set (newString) { if countElements(newString) > 0 { self.initial = newString.substringToIndex(advance(newString.startIndex, 1)) } else { self.initial = "" } } get { return self.initial } } }

Özellikler burada daha ayrıntılı olarak açıklanmıştır

Devam edecek

Generics, Objective-C kitaplıkları ile etkileşim, kapatmalar, isteğe bağlı zincirleme ve operatör aşırı yüklemesi gibi Swift'de öğrenilecek çok daha önemli yeni şeyler var. Tek bir öğretici, yeni bir dili tam olarak tanımlayamaz, ancak Swift programlamayı öğrenmek hakkında çok daha fazlasının yazılacağından şüphem yok. Ancak, bu hızlı okumanın , Swift dilinin ayrıntılarını öğrenmeyi ve zaman bulmayı başaramayan birçok Objective-C geliştiricisinin doğru yola girmesine ve Swift kuşunun onları yeni zirvelere taşımasına yardımcı olacağına inanıyorum.