Ağustos 18, 2024 /
24 dk /
#test
Kıssadan hisse: 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çinlet
kullan.
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.22print(type(of: double))
Double
Data 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_000
Float 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.2let num2 = 5print(num1 + Double(num2))
6.2
- Yuvarlamak için
.rounded()
kullanılabilir.
let x = 3.14print(x.rounded())print(x.rounded(.down))print(x.rounded(.up))
3.03.04.0
Boolean
var isSuccess = true
Collections
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
append
metodu kullanılır. Birden fazla değer eklemek içincontentsOf
parametresi kullanılır. Belirli indekse eleman eklemek istersekinsert
metodu 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
remove
veremoveLast
kullanı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 + secondHalf
Set
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
nil
yerine 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
enum
ismini 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
Comparable
protokolü 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
fallthrough
kullanılabilir. - Belirli değer aralığında mı diye kontrol etmek için
range
operatör kullanılabilir.1..<5
ve1...5
arası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
in
opeatö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}
1234
Repeat (aka Do-While)
var number = 1
repeat { print(number) number += 1} while number < 1
1
Functions
func square(number: Int) -> Int { return number * number}
let result = square(number: 8)
- Fonksiyon tek bir ifade içeriyorsa
return
atlanabilir.
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
throws
keyword 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
inout
anahtar kelimesi kullanabiliriz.
func doubleInPlace(number: inout Int) { return number *= 2}var myNum = 10doubleInPlace(number: &myNum)print(myNum)
20
Closure
{ (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 London
Error handling
- Hata fırlatabilecek bir kod çalıştıracaksak
do
bloğu içinde kullanmalıyız. Hata fırlatabilecek fonksiyonun başınatry
konur. 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
nil
dö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 tennis
Initializer
- Varsayılan olarak memberwise initializer ile gelir. Manuel işlemek için
init()
kullanabiliriz. -
self
mevcut instance’a işaret eder.init
haricinde kullanmamalıyız.
// usage 1: memberwisestruct 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
lazy
anahtar 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)
2
Property observe
- Değeri değiştiğinde ve değişmeden önce bir işlem gerçekleştirmek için
didSet
vewillSet
kullanı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 = 30progress.amount = 80progress.amount = 100
Loading data is now 30% completeLoading data is now 80% completeLoading data is now 100% complete
Mutating
- Varsayılan olarak metotların içinde property değiştirilemez yani constant struct’tır. Buna izin vermek için
mutating
anahtar kelimesi kullanılır.
struct Person { var name: String mutating func makeAnonymous() { name = "Anonymous" }}
var person = Person(name: "Ed")person.makeAnonymous()
Access control
-
public
veprivate
property 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ı
final
ile tanımlayabiliriz. Kritik bir şey yapıyorsanız override edilmemesi için bunu uygulayabilirsiniz. - Metodu override etmek için
override
anahtar 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
mutating
anahtar kelimesine ihtiyacı yok. - Bir property’nin immutable olması için
let
ile 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 let
veguard let
ile 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 coalescing
kullanı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 chaining
kullanı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 }}