Ağustos 18, 2024 /
24 dk /
Short notes about Swift
Yaşayan Yazı, bir yerimden uydurduğum bir terimdir ve ileriki dönemde içeriği zenginleşebilecek ama şu anki haliyle de faydalı olabilecek yazıları belirtir.
Variables
- Değişkenler için
var, constant içinletkullan.
var age = 24let PI = 3.14159- Temel değerlerin tipler type inference ile otomatik algılanır. Ancak initialize edilmiyorsa type annotation verilmelidir.
let year = 1999let year: Int = 1999var name: Stringname = "Enes"- Değişkenlerin türlerini öğrenmek için
type()kullanılabilir.
> let double: Double = 5.22> print(type(of: double))
DoubleData Types
String
var name = "Enes"- Çok satır metinler için üç tırnak kullan. Yeni satıra inmesini engellemek için satır sonuna
\ekle.
var address = """Y Mahallesi \X Sokak No:1 Kat:5Kadıköy/Türkiye"""- Dinamik string’ler için string interpolation kullan.
// example 1:var score = 85var str = "Your score was \(score)"// example 2:var greeting = "Hi, \(user ?? "Anonymous")"- String’in boş olup olmadığını kontrol etmek için
.isEmpty()kullan.
Integer
var age = 24var population = 8_000_000Float and Double
let justOverOneMillion = 1_000_000.000_000_1let PI: Float = 3.14159- Varsayılan noktalı değer tipi Double’dır. Float oluşturmak için tip tanımlamalıyız.
- Int bir değerle toplarken otomatik tür dönüşümü yapılmaz. Bunu yerine
Double()kullanılabilir.
> let num1 = 1.2> let num2 = 5> print(num1 + Double(num2))
6.2- Yuvarlamak için
.rounded()kullanılabilir.
> let x = 3.14> print(x.rounded())> print(x.rounded(.down))> print(x.rounded(.up))
3.03.04.0Boolean
var isSuccess = trueCollections
Array
var emptyArray = [Int]()var emptyArray2: [Int] = []var emptyArray3: Array<Float> = Array()var emptyArray4 = Array<Int>()let beatles = ["John Lennon", "Paul McCartney", "George Harrison", "Ringo Starr"]let numbers: [Int] = [1, 10, 5, 7]- Array annotation’ları
[String]ve[Boolean]gibi tanımlanabilir. - Değer okunurken köşeli parantez kullanımı uygulanır ve yoksa hata verir.
let beatles = ["John Lennon", "Paul McCartney", "George Harrison", "Ringo Starr"]beatles[1]beatles[12] // crash verir- Sona değer eklemek için
appendmetodu kullanılır. Birden fazla değer eklemek içincontentsOfparametresi kullanılır. Belirli indekse eleman eklemek istersekinsertmetodu kullanılır.
> var students = ["Ben", "Ivy", "Jordell"]> students.append("Maxime")> students.append(contentsOf: ["Shakia", "William"])> students.insert("Liam", at: 3)> print(students)
["Ben", "Ivy", "Jordell", "Liam", "Maxime", "Shakia", "William"]- Eleman silmek için
removeveremoveLastkullanılır.
> var students = ["Ben", "Ivy", "Jordell", "Liam", "Maxime", "Shakia"]> students.remove(at: 0)> students.removeLast()> print(students)
["Ivy", "Jordell", "Liam", "Maxime", "Shakia"]- Array’in slice etmek için range operatör kullanılabilir.
> let names = ["Piper", "Alex", "Suzanne", "Gloria"]> print(names[1...3])> print(names[2...])
["Alex", "Suzanne", "Gloria"]["Suzanne", "Gloria"]- İki array’i birleştirmek için artı operatörü kullanılabilir. Bu operator overloading olarak geçer.
let firstHalf = ["John", "Paul"]let secondHalf = ["George", "Ringo"]let beatles = firstHalf + secondHalfSet
> var emptySet1 = Set<String>()> var emptySet2: Set<String> = Set()> let colors = Set(["red", "green", "blue", "red", "blue"])> print(colors)
["red", "green", "blue"]- Unordered’dır ve öğeler benzersizdir. Bu sayede arama işlemleri çok hızlı gerçekleşir.
- Tanımlamak için
Set()fonksiyonu kullanılır.
Tuple
let name = (first: "Taylor", last: "Swift")- Birkaç değeri tek değerde saklamanıza izin verir.
- Boyutu sabittir yani öğe eklenemez ve çıkarılamaz. Ancak değerler değiştirilebilir.
- Dictionary’den farklı olarak bir değerin var olduğu garantidir ve boyutu büyüyemez.
- Erişmek için index ve key kullanılır.
print(name.0)print(name.first)Dictionary
var emptyDict1 = [String: String]()var emptyDict2: [String: String] = [:]var emptyDict3 = Dictionary<String, Int>()let person = [ "name": "Enes Başpınar", "aeg": 24]var responseMessages = [ 200: "OK", 403: "Access forbidden", 404: "File not found", 500: "Internal server error"]- Değer okunurken key yoksa
nilyerine varsayılan değer döndürülebilir.
favoriteIceCream["Charlotte", default: "Unknown"]Enum(eration)
enum Result { case success case failure}- İlişkili değerleri bir arada tutar.
- Değer olarak kullanırken tip tanımlanmışsa
enumismini kullanmaya gerek yoktur.
var result: Result = Result.success;var result2: Result = .success;- Enum değerlerine raw index ile de erişebiliriz.
enum Planet: Int { case mercury = 1 case venus case earth case mars}
let earth = Planet(rawValue: 3)- Enum değerleri ilişkili değerleri de depolayabilir.
enum Activity { case bored case running(destination: String) case talking(topic: String) case singing(volume: Int)}
let talking = Activity.talking(topic: "football")- Enum değerlerini karşılaştırılabilir hale getirmek için
Comparableprotokolü kullanılabilir.
enum Sizes: Comparable { case small case medium case large}
print(Sizes.small < Sizes.large)Conditions
- String’lerde alfabetik sıra olduğu için büyüktür küçüktür kullanılabilir. Örneğin
"Taylor" <= "Swift".
If else
let firstCard = 11let secondCard = 10
if firstCard + secondCard == 2 { print("Aces – lucky!")} else if firstCard + secondCard == 21 { print("Blackjack!")} else { print("Regular cards")}Ternary operator
print(isLoggedIn ? "Welcome." : "Please login.")Switch
switch weather {case "rain": print("Bring an umbrella")case "snow": print("Wrap up warm")case "sunny": print("Wear sunscreen") fallthroughdefault: print("Enjoy your day!")}- Eğer altındaki case’e devam etmesi için
fallthroughkullanılabilir. - Belirli değer aralığında mı diye kontrol etmek için
rangeoperatör kullanılabilir.1..<5ve1...5arasındaki fark son değerin dahil edilip edilmediğidir.
let score = 85
switch score {case 0..<50: print("You failed badly.")case 50..<85: print("You did OK.")default: print("You did great!")}Loops
For
// example 1:for number in 1...5 { print("Number is \(number)")}// example 2:let names = ["Sterling", "Cyril", "Lana", "Ray", "Pam"]for _ in names { print("[CENSORED] is a secret agent!")}- Array iterate etmek için
inopeatörü kullanılabilir.
let albums = ["Red", "1989", "Reputation"]
for album in albums { print("\(album) is on Apple Music")}While
> var number = 1>> while number <= 4 {> print(number)> number += 1> }
1234Repeat (aka Do-While)
> var number = 1>> repeat {> print(number)> number += 1> } while number < 1
1Functions
func square(number: Int) -> Int { return number * number}
let result = square(number: 8)- Fonksiyon tek bir ifade içeriyorsa
returnatlanabilir.
func isUppercase(string: String) -> Bool { string == string.uppercased()}
func greet(name: String) -> String { name == "Taylor Swift" ? "Oh wow!" : "Hello, \(name)"}- Birden çok değer döndürmek istiyorsak tuple kullanabiliriz.
> func getUser() -> (firstName: String, lastName: String) {> return (firstName: "Taylor", lastName: "Swift")> // ya da return ("Taylor", "Swift")> }> let (firstName, lastName) = getUser()> print("Name: \(firstName) \(lastName)")
Name: Taylor Swift- Parametrelere fonksiyon çalıştırırken kullanmak üzere label atayabiliriz.
> func sayHello(to name: String) {> print("Hello, \(name)!")> }>> sayHello(to: "Taylor")
Hello, Taylor!- Parametre label’ını es geçmek için
_kullanılabilir.
> func greet(_ person: String, nicely: Bool = true) {> if nicely == true {> print("Hello, \(person)!")> } else {> print("Oh no, it's \(person) again...")> }> }>> greet("Taylor")> greet("Taylor", nicely: false)
Hello, Taylor!Oh no, it's Taylor again...- Variadic fonksiyon parametresi tanımlamak için tipinin sonuna
...eklenir. Parametre gönderilmezse değeri[]olur.
> func square(_ numbers: Int...) {> for number in numbers {> print("\(number) squared is \(number * number)")> }> }>> square(1, 2, 3, 4, 5)
1 squared is 12 squared is 43 squared is 94 squared is 165 squared is 25- Fonksiyon çalışırken hata fırlatmak için
throwskeyword kullanılabilir.
enum LoginErrors: Error { case badUsername case badPassword}
func login(username: String, password: String) throws -> Bool { if username.isEmpty { throw LoginErrors.badUsername } if password.isEmpty { throw LoginErrors.badPassword } return true}- Fonksiyon parametreleri constant’tır. Parametre değiştiğinde orjinalinin de değişmesini istersek
inoutanahtar kelimesi kullanabiliriz.
> func doubleInPlace(number: inout Int) {> return number *= 2> }> var myNum = 10> doubleInPlace(number: &myNum)> print(myNum)
20Closure
{ (parameters) -> returnType in // statements}- İsmi olmayan özel bir fonksiyon türüdür.
- Değişkene atanabilir.
var greet = { print("Hello, World!")}
greet()- Parametre alabilir. Fonksiyondan farklı olarak çağırırken parametre adını vermek gerekmez.
let greetUser = { (name: String) in print("Hey there, \(name).")}
greetUser("Delilah")- Değer döndürebilir.
// usage 1:var findSquare = { (num: Int) -> (Int) in var square = num * num return square}
// usage 2:var findSquare = { (num: Int) -> Int in num * num }
// usage 3:var findSquare: (Int) -> Int = { num in num * num }
// usage 4:var findSquare: (Int) -> Int = { $0 * $0 }
var result = findSquare(3)- Başka fonksiyona parametre olarak iletilebilir.
func grabLunch(search: () -> ()) { search()}
grabLunch(search: { print("Alfredo's Pizza: 2 miles away")})- Fonksiyonun son parametresi closure ise trailing closure dediğimiz özel sözdizimi kullanabilir.
> func grabLunch(message: String = "", search: () -> ()) {> if (message != "") {> print(message)> }> search()> }>> grabLunch(message:"Let's go out for lunch") {> print("Alfredo's Pizza: 2 miles away")> }>> grabLunch {> print("Alfredo's Pizza: 2 miles away")> }
Let's go out for lunchAlfredo's Pizza: 2 miles away- Referans tiplidir.
- Tanımlandığı bağlamda bulunan değişkenlerin referanslarını saklar.
> func travel() -> (String) -> Void {> var counter = 1>> return {> print("\(counter). I'm going to \($0)")> counter += 1> }> }>> let makeTravel = travel()> makeTravel("London")> makeTravel("London")> makeTravel("London")
1. I'm going to London2. I'm going to London3. I'm going to LondonError handling
- Hata fırlatabilecek bir kod çalıştıracaksak
dobloğu içinde kullanmalıyız. Hata fırlatabilecek fonksiyonun başınatrykonur. Hata fırlattığındacatch’e düşer.
enum PasswordError: Error { case obvious}
func checkPassword(_ password: String) throws -> Bool { if password == "password" { throw PasswordError.obvious } return true}
do { try checkPassword("password") print("That password is good!")} catch { print("You can't use that password.")}- Başarısız olduğunda
nildönmesini isterseniztry?kullanabilirsiniz.
if let result = try? checkPassword("password") { print("Result was \(result)")} else { print("D'oh.")}Struct
- Özel değişken tipi oluşturmanın en yaygın yoludur.
> struct Sport {> var name: String> }>> var tennis = Sport(name: "Tennis")> print(tennis.name)> tennis.name = "Lawn tennis"> print(tennis.name)
TennisLawn tennisInitializer
- Varsayılan olarak memberwise initializer ile gelir. Manuel işlemek için
init()kullanabiliriz. -
selfmevcut instance’a işaret eder.initharicinde kullanmamalıyız.
> // usage 1: memberwise> struct Employee {> var name: String> var yearsActive = 0> }>> let roslin = Employee(name: "Laura Roslin")> let adama = Employee(name: "William Adama", yearsActive: 45)>> // usage 2:> struct Employee {> var name: String> var yearsActive = 0> init() {> self.name = "Anonymous"> print("Creating an anonymous employee…")> }> }>> var roslin = Employee()> roslin.name = "Laura Roslin">> // usage 3:> struct Employee {> var name: String> var yearsActive = 0> init(name: String) {> self.name = name> }> }>> var roslin = Employee(name: "Laura Roslin")
Creating a new user!Property
- Eğer bir property’nin ilk erişildiğinde hesaplanmasını istiyorsak
lazyanahtar kelimesini kullanabiliriz. Hesaplama maliyeti nesne oluşturulurken atlanmış olur. Sonraki her çağrılışta hesaplanan sonucu bellekten döndürür.
> struct FamilyTree {> init() {> print("Creating family tree!")> }> }>> struct Person {> var name: String> lazy var familyTree = FamilyTree()>> init(name: String) {> self.name = name> }> }>> let ed = Person(name: "Ed")> let edFamilyTree = ed.familyTree
Creating family tree!Computed property
- Başka bir property değerine göre hesaplanan property’lerdir. Ağır hesaplamalar için metod kullanmak daha iyidir.
struct Sport { var name: String var isOlympicSport: Bool var olympicStatus: String { return isOlympicSport ? "\(name) is an Olympic sport" : "\(name) is not an Olympic sport" }
func play() { // ... }}
let chessBoxing = Sport(name: "Chessboxing", isOlympicSport: false)print(chessBoxing.olympicStatus)Static property
> struct Student {> static var classSize = 0> var name: String>> init(name: String) {> self.name = name> Student.classSize += 1> }> }>> let ed = Student(name: "Ed")> let taylor = Student(name: "Taylor")> print(Student.classSize)
2Property observe
- Değeri değiştiğinde ve değişmeden önce bir işlem gerçekleştirmek için
didSetvewillSetkullanılır.
> struct Progress {> var task: String> var amount: Int {> didSet {> print("\(task) is now \(amount)% complete")> }> }> }>> var progress = Progress(task: "Loading data", amount: 0)> progress.amount = 30> progress.amount = 80> progress.amount = 100
Loading data is now 30% completeLoading data is now 80% completeLoading data is now 100% completeMutating
- Varsayılan olarak metotların içinde property değiştirilemez yani constant struct’tır. Buna izin vermek için
mutatinganahtar kelimesi kullanılır.
struct Person { var name: String mutating func makeAnonymous() { name = "Anonymous" }}
var person = Person(name: "Ed")person.makeAnonymous()Access control
-
publicveprivateproperty ve metodlara nereden erişilebileceğini tanımlar.
struct Person { private var id: String
init(id: String) { self.id = id }
func identify() -> String { return "My social security number is \(id)" }}Class
> class Dog {> var name: String> var breed: String>> init(name: String, breed: String) {> self.name = name> self.breed = breed> }> }>> let poppy = Dog(name: "Poppy", breed: "Poodle")- Referans tiplidirler yani instance’ların referansı aynıdır.
- Inheritance yapmak için ilgili sınıf annotation ile belirtilebilir.
class Dog { var name: String var breed: String
init(name: String, breed: String) { self.name = name self.breed = breed }}
class Poodle: Dog { init(name: String) { super.init(name: name, breed: "Poodle") }}- Inherit edilmemesini istediğimiz fonksiyonları
finalile tanımlayabiliriz. Kritik bir şey yapıyorsanız override edilmemesi için bunu uygulayabilirsiniz. - Metodu override etmek için
overrideanahtar kelimesi kullanılır.
> class Dog {> func makeNoise() {> print("Woof!")> }> }>> class Poodle: Dog {> override func makeNoise() {> print("Yip!")> }> }>> let poppy = Poodle()> poppy.makeNoise()
Yip!- Nesne yok edildiğinde bir işlem yapmak için deinitializer tanımlanabilir.
> class Person {> var name = "John Doe">> init() {> print("\(name) is alive!")> }>> deinit {> print("\(name) is no more!")> }>> func printGreeting() {> print("Hello, I'm \(name)")> }> }>> for _ in 1...3 {> let person = Person()> person.printGreeting()> }
John Doe is alive!Hello, I'm John DoeJohn Doe is no more!John Doe is alive!Hello, I'm John DoeJohn Doe is no more!John Doe is alive!Hello, I'm John DoeJohn Doe is no more!- Sınıf sabit olarak oluşturulduğunda bile bir sınıf üzerindeki property’ler değiştirebilir. Dolayısıyla
mutatinganahtar kelimesine ihtiyacı yok. - Bir property’nin immutable olması için
letile constant olarak tanımlanabilir.
Protocol
- Bir şeyin hangi property ve metodlara sahip olması gerektiğini tanımlar. Java interface’lerine çok benzerdir.
protocol Purchaseable { var name: String { get set }}
struct Book: Purchaseable { var name: String var author: String}
struct Movie: Purchaseable { var name: String var actors: [String]}
struct Car: Purchaseable { var name: String var manufacturer: String}
func buy(_ item: Purchaseable) { print("I'm buying \(item.name)")}- Protocol’lerde inheritance destekler.
// bad usage:protocol Computer { var price: Double { get set } var weight: Int { get set } var cpu: String { get set } var memory: Int { get set } var storage: Int { get set }}
protocol Laptop { var price: Double { get set } var weight: Int { get set } var cpu: String { get set } var memory: Int { get set } var storage: Int { get set } var screenSize: Int { get set }}
// good usage:protocol Product { var price: Double { get set } var weight: Int { get set }}
protocol Computer: Product { var cpu: String { get set } var memory: Int { get set } var storage: Int { get set }}
protocol Laptop: Computer { var screenSize: Int { get set }}Extension
- Orjinalini bozmadan mevcuttaki tiplere ekstra metodlar eklemenize izin verir.
extension Int { var isEven: Bool { return self % 2 == 0 }
func squared() -> Int { return self * self }}
let number = 8print(number.squared())print(number.isEven)- Protokoldeki metodlara varsayılan implementasyon vermek için protocol extension kullanılabilir. Protocol inherit eden her yeri etkiler.
extension Collection { func summarize() { print("There are \(count) of us:")
for name in self { print(name) } }}
let pythons = ["Eric", "Graham", "John", "Michael", "Terry", "Terry"]let beatles = Set(["John", "Paul", "George", "Ringo"])
pythons.summarize()beatles.summarize()Optionals
- Bir değerin olmayabileceğini (
nil) belirtir.
var age: Int? = nilage = 38- Optional değerler direk kullanılmaz ve unwrapping yapmak gerekir.
if letveguard letile yapılabilir:
func getUsername() -> String? { "Taylor" }
if let username = getUsername() { print("Username is \(username)")} else { print("No username")}func greet(_ name: String?) { guard let unwrapped = name else { print("You didn't provide a name!") return }
print("Hello, \(unwrapped)!")}- Bazen bir değerin nil olmadığından eminsinizdir. Bu durumda force unwrapping kullanılabilir.
!aynı zamanda crash operator olara isimlendirilir.
// usage 1:enum Direction: CaseIterable { case north, south, east, west}
let randomDirection = Direction.allCases.randomElement()!
// usage 2:enum Direction: CaseIterable { case north, south, east, west
static func random() -> Direction { Direction.allCases.randomElement()! }}
let randomDirection = Direction.allCases.randomElement()!- Bir değerin sadece tanımlarken nil olduğunu ancak kullanırken her zaman dolu olacağını biliyorsak direk unwrapped optional olarak tanımlayabiliriz.
let age: Int! = nil- Değer nil olduğunda varsayılan belirtmek için
nil coalescingkullanılır. Birden fazla zincirlenebilir.
func username(for id: Int) -> String? { return id == 1 ? "Taylor Swift" : nil}
let user = username(for: 15) ?? "Anonymous"- Nil olabilecek bir nesneden değer okuyacaksak crash almamak için
optional chainingkullanılabilir.
let names = ["Vincent": "van Gogh", "Pablo": "Picasso", "Claude": "Monet"]let surnameLetter = names["Vincent"]?.first?.uppercased()- Initializer’da nesne oluşturma enasında problem yaşadığınızda nil dönmek isterseniz
init?kullanabilirsiniz.
struct Employee { var username: String var password: String
init?(username: String, password: String) { guard password.count >= 8 else { return nil } guard password.lowercased() != "password" else { return nil }
self.username = username self.password = password }}