Podsumowanie: Listopad 2023

Opublikowano: 30.11.2023 - tagi: Blog Podsumowanie Listopad 2023

We listopadzie opublikowałem 6 wpisów:


Swfit

  1. Klasy
  2. Protokoły
  3. Kontrola dostępu
  4. Extension

Narysowałem dwa komiksy:

  1. Coding rules
  2. Face the problem

Przeczytałem dwie książki:

  1. Outpost 2 — Dmitry Glukhovsky
  2. Dawno temu w Warszawie — Jakub Żulczyk

Przesłuchałem pięć audiobooki:

  1. Rozjemca — Brandon Sanderson
  2. Powróceni — Abdulrazak Gurnah
  3. Zło ze wschodu — Andrzej Pilipiuk
  4. Legion — Elżbieta Cherezińska
  5. Ziemiomorze. Czarnoksiężnik z Archipelagu — Ursula K. Le Guin

Comics: Face the problem

Opublikowano: 23.11.2023 - tagi: Komiks Rysowanie

Face the problem

Swift: Extension

Opublikowano: 21.11.2023 - tagi: Swift Struktura Klasa Protokół Typ Rozszerzenie

Rozszerzenia

Rozszerzenia w Swift służą do dodania funkcjonalności do już istniejącego typu. Może to być typ zarówno wbudowany w język, jak i stworzony przez programistę.

Rozszerzenie można dodać do klasy, struktury, protokołu, enumeracji i innych typów w Swift.

Żeby dodać nowe rozszerzenie, należy użyć słowa kluczowego extension.

Za pomocą rozszerzenie możesz dodać nową funkcjonalność, ale nie możesz nadpisać już istniejącej.

Przykłady

Typ własny

class Calculator {
	func add(a: Int, b: Int) -> Int {
		return a + b
	}
}

extension Calculator {
	func subtract(a: Int, b: Int) -> Int {
		return a - b
	}
}

var calculator = Calculator()

print(calculator.add(a: 7, b: 3)) // 10
print(calculator.subtract(a: 7, b: 3)) // 4

Typ wbudowany

Możesz też dodać rozszerzenie do typu wbudowanego:

extension Int {
	func square() -> Int {
	    return self * self
	}
}

var a: Int = 7
print("a * a =  \(a.square())") // 49
print("a = \(a)") // 7

Jeśli chcesz zmienić stan użyj słowa kluczowego mutating i nową wartość przypisz do self:

extension Int {
	mutating func square() {
	    self = self * self
	}
}

var a: Int = 7
a.square()
print("a = \(a)") // 49
a.square()
print("a = \(a)") // 2401

Computed property

Za pomocą rozszerzenia nie możesz dodać stored property:

extension SomeType {
	var property1: Int // Błąd!
}

ale możesz dodać computed property:

struct User {
	var firstName: String = ""
	var lastName: String = ""
}

extension User {
	var fullName: String {
		return firstName + " " + lastName
	}
}

var user = User(firstName: "James", lastName: "Bond");
print(user.fullName) // James Bond

Swift: Kontrola dostępu

Opublikowano: 16.11.2023 - tagi: Swift Klasa Struktura Dostęp

Kontrola dostępu w Swift

Dzięki kontroli dostępu możesz określić dostępność klas, struktur, enumeracji, protokołach, właściwości, metod itp.

Swift udostępnia kilka poziomów dostępu.

Są to:

  1. open
  2. public
  3. private
  4. fileprivate
  5. internal

Dostęp: open

Poziom dostępu open pozwala na to, że każdy ma do tego dostęp: zarówno z poziomu modułu jak i z zewnątrz.

Dzięki temu możesz pozwolić sobie także na nadpisywanie.

Jest to najmniej restrykcyjnym poziomem dostępu w Swift.

Dostęp: public

Jeśli określisz coś jako public to znaczy, że informujesz, że każdy może mieć do tego dostęp.

Podobne do open, ale różnica między nimi jest taka, że masz do tego dostęp wszędzie, ale nie możesz sobie pozwolić na nadpisanie z poziomu innego modułu.

Na przykład:

class MyClass {
	public name: String = ""
}

var obj = MyClass()

obj.name = "Public"

print(obj.name) // Public

Dostęp: private

private sprawia, że dostęp jest ograniczony do danego zakresu.

class User {
	private firstName: String = ""
	private lastName: String = ""
	
	init(firstName: String, lastName: String) {
		self.firstName = firstName
		self.lastName = lastName
	}
	
	func getFullName() -> String {
		return "\(firstName) \(lastName)"
	}
}

var user = User(firstName: "Jan", lastName: "Kowalski")

print(user.getFullName())

user.firstName = "Adam" // Błąd!

Dostęp: fileprivate

Ten poziom dostępu podobny jest do private. Różnica jest taka, że dostęp jest ograniczony w obrębie pliku.

class User {
	fileprivate firstName: String = ""
	fileprivate lastName: String = ""
	
	init(firstName: String, lastName: String) {
		self.firstName = firstName
		self.lastName = lastName
	}
	
	func getFullName() -> String {
		return "\(firstName) \(lastName)"
	}
}

var user = User(firstName: "Jan", lastName: "Kowalski")

print(user.getFullName()) // Jan Kowalski

user.firstName = "Adam" 

print(user.getFullName()) // Adam Kowalski

Jeśli spróbujesz się dostać do firstName lub lastName w innym pliku, zostanie zgłoszony błąd.

Inny przykład:

fileprivate class MyClass {
	name: String = ""
}

Tak oznaczoną klasę: MyClass możesz używać tylko w pliku, w którym jest stworzona.

Dostęp: internal

internal to domyślny poziom dostępu w Swift.

Czyli zapis:

class MyClass {
	...
}

jest równoznaczny z:

internal class MyClass {
	...
}

A co to robi? W taki sposób informujemy, że kod jest dostępny w obrębie modułu, ale na zewnątrz już nie.


Swift: Protokoły

Opublikowano: 09.11.2023 - tagi: Swift Klasa Struktura

Protokoły w Swift

W Swift protokoły działają w podobny sposób, jak interfejsy w innych językach programowania.

Za pomocą protokołu możesz rozszerzyć swoją klasę, strukturę lub enumerację o nowe właściwości i metody.

W przypadku klasy jest to przydatne, ponieważ klasę w Swift można dziedziczyć, tylko po jednej klasie.

Jeśli chodzi o struktury, tutaj jest większy problem. Struktury nie można rozszerzyć poprzez dziedziczenie. W tym przypadku ten problem rozwiązują protokoły.

Definicja protokołu

Protokół stworzysz za pomocą słowa kluczowego protocol:

protocol Fly {
    var maximumSpeed: Int { get }
	
    func fly()
}

Ponieważ protokół jest typem, jego nazwa musi zaczynać się od dużej litery.

W protokole umieszcza tylko się definicje właściwości i metod.

Składnia deklaracji właściwości wygląda tak:

var someProperty: Type { get set }

get i set służą do poinformowania, że dana zmienna jest tylko do: odczytu (get), zapisu (set) lub zarówno do odczytu jak i zapisu (get set).

Jeśli oznaczysz właściwość jako get i set:

protocol Fly {
  var maximumSpeed: Int { get set }
}

I zastosujesz ten protokół, w taki sposób, że ta właściwość będzie computed property, zostanie zgłoszony błąd:

struct Bird: Fly {
    var energy: Int = 100
    var maximumSpeed: Int {  // Błąd!
        return energy + 50
    }
}

Jest tak dlatego, bo maximumSpeed zostało oznaczone jako set, a do computed property nie można przypisać wartości.

Implementacja protokołu

Zastosowanie protokołu wygląda tak samo, jak dziedziczenie:

class Bird: Fly {
	var maximumSpeed: Int = 50
	
	func fly() {
		print("Bird is flying with maximum speed: \(maximumSpeed)")
	}
}

class Plane: Fly {
	var maximumSpeed: Int = 1000
	
	func fly() {
		print("Plane is flying with maximum speed: \(maximumSpeed)")
	}
}

var bird = Bird()
bird.fly() // Bird is flying with maximum speed: 50

var plane = Plane()
plane.fly() // Plane is flying with maximum speed: 1000

Wiele protokołów

Swift pozwalana na zastosowanie wielu protokołów:

protocol Fly {	
	func fly()
}

protocol Eat {
	func eat()
}

class Bird: Fly, Eat {	
	func fly() {
		print("Bird is flying")
	}
	
	func eat() {
		print("Bird is eating")
	}
}

var bird = Bird()
bird.fly() // Bird is flying 
bird.eat() // Bird is eating

Dziedziczenie protokołów

Możesz także dziedziczyć po... innym protokole:

protocol A {
	func doA()
}

protocol SomeProtocol: A {
	func doSomething()
}

class MyClass: SomeProtocol {
	func doA() {
		print("Call doA")
	}
	
	func doSomething() {
		print("Call doSomething")
	}
}

Istnieje możliwość dziedziczenia po wielu protokołach:

protocol A {
	func doA()
}

protocol SomeProtocol: A {
	func doSomething()
}

class MyClass: SomeProtocol {
	func doA() {
		print("Call doA")
	}
	
	func doSomething() {
		print("Call doSomething")
	}
}

Struktury i protokoły

Jeśli zamierzasz zastosować protokół do struktury, a ten posiada metodę, której implementacja w strukturze będzie działać na zasadzie zmiany stanu struktury, musisz użyć dla tej metody słowa kluczowego mutating.

Przykład:

protocol Counter {
    var counter: Int { get }
	mutating func increment()
	mutating func decrement()
}
struct MyCounter: Counter {
	var counter = 0
	
	mutating func increment() {
		counter += 1
	}
	
	mutating func decrement() {
	    counter -= 1
	}
}
var myCounter = MyCounter()
myCounter.increment()
myCounter.increment()
myCounter.decrement()

print("Counter: \(myCounter.counter)")