Ang Swift ay programming language ng Apple na pinagsasama ang kapangyarihan ng Objective-C sa kaligtasan ng mga modernong wika. Hindi tulad ng maraming iba pang mga wika, nag-aalok ang Swift ng mga natatanging konstruksyon: mga uri ng halaga na may awtomatikong pagkopya, Actors na may paghihiwalay sa antas ng compiler, Property Wrappers para sa muling paggamit ng lohika ng pag-aari, at Protocol Oriented Programming bilang alternatibo sa klasikong pamana. Ayon sa Dokumentasyon ng Apple Swift, ang mga tampok na ito ay ginagawang mas ligtas at mahusay ang code.
Mga Pangunahing Punto
Sa Swift, ang struct ay isang uri ng halaga, habang ang class ay isang uri ng sanggunian. Ang pangunahing pagkakaiba na ito ay tumutukoy sa pag-uugali sa panahon ng pagtatalaga, pagpasa sa mga function, at pamamahala ng memorya. Ang struct ay kinokopya nang buo sa bawat pagtatalaga, ang class ay ipinapasa sa pamamagitan ng sanggunian — ang pointer lamang sa heap object ang kinokopya.
Awtomatikong ipinapatupad ng Struct ang semantika ng halaga — ang bawat instance ay independyente. Ang pagbabago ng pag-aari ng struct ay posible lamang sa pamamagitan ng var, at ang mga pamamaraan na nagbabago ng mga pag-aari ay dapat markahan bilang mutating. Hindi sinusuportahan ng Struct ang pamana ngunit maaaring sumunod sa mga protocol. Ang standard library ng Swift ay gumagamit ng struct para sa String, Array, Dictionary, Int, Bool — lahat ng pangunahing uri ay mga uri ng halaga.
struct User {
let id: Int
var name: String
mutating func updateName(_ newName: String) {
name = newName
}
}
var user1 = User(id: 1, name: "Alice")
var user2 = user1
user2.updateName("Bob")
// user1.name === "Alice", user2.name === "Bob"
// Buong kopya — mga independyenteng instance
Ang Class ay naka-imbak sa heap at sumusuporta sa pagkakapantay-pantay ng sanggunian. Maraming mga variable ang maaaring sumangguni sa parehong bagay, ang mga pagbabago sa pamamagitan ng isang sanggunian ay nakikita sa lahat ng iba pa. Sumusuporta ang Class sa pamana, nagpapahintulot sa pag-override ng pamamaraan (override), may deinit para sa paglilinis ng mga mapagkukunan. Sa Swift, ang class ay mas madalas na ginagamit kaysa sa struct — inirerekomenda ng Apple na magsimula sa struct at lumipat sa class lamang kapag kailangan ang pamana o semantika ng sanggunian.
class Car {
let model: String
var speed: Int
init(model: String, speed: Int) {
self.model = model
self.speed = speed
}
func accelerate(_ amount: Int) {
speed += amount
}
}
let car1 = Car(model: "Tesla", speed: 0)
let car2 = car1
car2.accelerate(50)
// car1.speed === 50, car2.speed === 50
// Parehong sanggunian — nakikita ang mga pagbabago kahit saan
Ang pagpili sa pagitan ng struct at class ay depende sa semantika ng data. Para sa mga pagsasaayos, modelo ng data at estado gamitin ang struct — mas ligtas at mas predictable ang pagkopya. Para sa mga bagay na may pagkakakilanlan (session ng gumagamit, koneksyon sa database) at kapag kailangan ang pamana, gamitin ang class.
Actor ay isang uri ng sanggunian na nagpoprotekta sa nababagong estado mula sa sabay-sabay na pag-access. Ginagarantiya ng Swift compiler na ang mga variable ng actor ay maaaring ma-access lamang mula sa parehong konteksto ng actor — anumang panlabas na pag-access ay nagdudulot ng error sa compilation. Pinipigilan nito ang data races sa antas ng wika, nang walang manu-manong pag-lock.
Lahat ng mga pag-aari at pamamaraan ng actor ay nakahiwalay bilang default. Ang pagtawag sa isang pamamaraan ng actor mula sa labas ay nangangailangan ng await — inililipat ng Swift ang pagpapatupad sa actor at pabalik. Isinasabay ng Actor ang pag-access nang sunud-sunod: ang mga kahilingan mula sa iba't ibang mga gawain ay nakapila. Ginagarantiya nito ang pare-parehong estado sa loob ng actor. Ang mga hindi nakahiwalay na pamamaraan (nonisolated) ay maaaring tawagan nang walang await ngunit hindi maaaring ma-access ang mga nababagong pag-aari.
actor BankAccount {
private var balance: Double
init(initialBalance: Double) {
balance = initialBalance
}
func deposit(amount: Double) {
balance += amount
}
func withdraw(amount: Double) throws {
guard balance >= amount else {
throw BankError.insufficientFunds
}
balance -= amount
}
nonisolated func accountInfo() -> String {
return "Bank Account"
}
}
let account = BankAccount(initialBalance: 1000)
await account.deposit(amount: 500)
// balance = 1500 — atomic, walang kondisyon ng karera
Ang Actor ay kapaki-pakinabang para sa mga tagapamahala ng estado, cache at mga serbisyo sa network kung saan maraming mga gawain ang sabay-sabay na nagbabasa at nagsusulat ng data. Hindi tulad ng manu-manong pag-synchronize sa pamamagitan ng NSLock o DispatchQueue, ang actor ay sinusuri sa oras ng compilation — imposibleng magkamali. Ang mga error sa paghihiwalay ay lilitaw sa oras ng compilation, hindi sa runtime.
Property Wrapper ay isang anotasyon na nagdaragdag ng pag-uugali sa isang pag-aari nang hindi binabago ang deklarasyon nito. Ang SwiftUI at Combine ay nagbibigay ng mga built-in na wrapper para sa pamamahala ng estado ng mga view. Ang compiler ay bumubuo ng code na bumabalot sa pag-access sa pag-aari, nagdaragdag ng lohika ng pagmamasid, pag-synchronize o pagbabago.
@Published ay ginagamit sa mga klase na sumusunod sa ObservableObject upang awtomatikong mag-publish ng mga pagbabago. Ang mga subscriber ng Combine ay tumatanggap ng mga abiso sa bawat update. @State ay ang lokal na estado ng isang SwiftUI view. Awtomatikong iginuhit muli ng SwiftUI ang view kapag nagbago ang @State. @Binding ay lumilikha ng dalawang-daanang koneksyon sa pagitan ng isang magulang at anak na view nang hindi nagmamay-ari ng data.
import SwiftUI
import Combine
@main
struct CounterApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
class CounterViewModel: ObservableObject {
@Published var count: Int = 0
func increment() {
count += 1
}
}
struct ContentView: View {
@State private var greeting: String = "Kumusta"
@StateObject private var viewModel = CounterViewModel()
var body: some View {
VStack {
CounterDisplay(count: $viewModel.count)
Text(greeting)
Button("Dagdagan", action: viewModel.increment)
}
}
}
struct CounterDisplay: View {
@Binding var count: Int
var body: some View {
Text("Bilang: \(count)")
}
}
Ang mga custom na Property Wrappers ay nilikha gamit ang @propertyWrapper at isang istraktura na may wrappedValue field. Ito ay nagpapahintulot sa muling paggamit ng lohika: pagpapatunay, normalisasyon, pag-iimbak ng UserDefaults. Ang Property Wrappers ay makabuluhang binabawasan ang boilerplate code at ginagawang tahasan ang intensyon ng developer sa pamamagitan ng anotasyon.
@propertyWrapper
struct Clamped<T: Comparable> {
private var value: T
let range: ClosedRange<T>
init(wrappedValue: T, range: ClosedRange<T>) {
self.range = range
self.value = min(max(wrappedValue, range.lowerBound), range.upperBound)
}
var wrappedValue: T {
get { value }
set { value = min(max(newValue, range.lowerBound), range.upperBound) }
}
}
struct Settings {
@Clamped(range: 0...100) var volume: Int = 50
}
var s = Settings()
s.volume = 150
// s.volume === 100 — awtomatikong nilimitahan ang halaga
Generics ay isang makapangyarihang mekanismo ng Swift para sa pagsulat ng flexible na code nang hindi nawawala ang kaligtasan ng uri. Ang mga generic na function at uri ay gumagana sa anumang uri na nakakatugon sa mga hadlang. Ang Protocol Oriented Programming (POP) ay isang paradigm ng Swift kung saan ang protocol + extension ay pumapalit sa klasikong pamana ng klase, na nagbibigay ng komposisyon ng pag-uugali.
Pinapayagan ng Swift na paghigpitan ang mga generic na parameter sa mga protocol (where clauses). Ang protocol na may kaugnay na uri ay ang generic na katumbas para sa mga protocol: ang konkretong uri ay tinutukoy sa oras ng pagsunod. Ito ang batayan para sa type-safe na mga koleksyon at algorithm. Ang standard library ng Swift ay aktibong gumagamit ng Generics: Array, Dictionary, Optional — lahat ay generic na uri.
protocol Cacheable {
associatedtype Key: Hashable
associatedtype Value
func get(_ key: Key) -> Value?
mutating func set(_ value: Value, for key: Key)
}
struct MemoryCache<K: Hashable, V>: Cacheable {
private var storage: [K: V] = [:]
typealias Key = K
typealias Value = V
func get(_ key: K) -> V? {
return storage[key]
}
mutating func set(_ value: V, for key: K) {
storage[key] = value
}
}
func firstMatch<T: Equatable>(in array: [T], target: T) -> Int? {
for (index, item) in array.enumerated() {
if item == target {
return index
}
}
return nil
}
let numbers = [10, 20, 30, 40]
let index = firstMatch(in: numbers, target: 30)
// index === 2 — isang generic na pamamaraan para sa lahat ng uri ng Equatable
Ang protocol extension ay isang pangunahing mekanismo ng POP. Sa isang extension, maaaring magbigay ng default na implementasyon ng mga pamamaraan ng protocol. Ang mga uri na sumusunod sa protocol ay nakakakuha ng implementasyong ito ng libre at maaaring i-override ito kung kinakailangan. Ito ay nagpapahintulot sa pagbuo ng hierarchy ng pag-uugali nang walang pamana ng klase — isang alternatibo sa maramihang pamana, na hindi umiiral sa Swift.
protocol Drivable {
var speed: Double { get set }
func drive()
}
extension Drivable {
func drive() {
if speed > 0 {
print("Nagmamaneho sa \(speed) km/h")
}
}
}
struct Bicycle: Drivable {
var speed: Double = 15
}
struct Plane: Drivable {
var speed: Double = 900
func drive() {
print("Lumilipad sa \(speed) km/h")
}
}
let bike = Bicycle()
bike.drive() // "Nagmamaneho sa 15.0 km/h" — default
let plane = Plane()
plane.drive() // "Lumilipad sa 900.0 km/h" — na-override
Ang POP na may extension ay nagbibigay-daan sa komposisyon sa pamamagitan ng maramihang mga protocol — isang uri ay maaaring sumunod sa maraming mga protocol, na nakakakuha ng kanilang mga implementasyon. Ito ay mas flexible kaysa sa solong pamana ng klase kung saan ang buong hierarchy ay naayos. Ang standard library ng Swift ay binuo sa POP: CustomStringConvertible, Equatable, Hashable, Codable — lahat ay mga protocol na may mga extension.
Enum sa Swift ay isang mas makapangyarihang konstruksyon kaysa sa ibang mga wika. Ang bawat kaso ay maaaring magkaroon ng kaugnay na mga halaga — isang arbitraryong hanay ng data ng anumang uri. Kapag pinagsama sa extension at pattern matching, ang enum ay nagiging batayan para sa pagmomodelo ng mga estado, resulta ng operasyon at finite state machine.
Ang kaugnay na mga halaga ay nagpapahintulot sa bawat kaso na mag-imbak ng natatanging data. Halimbawa, ang kaso ng loading ay walang data, ang success ay naglalaman ng resulta, ang failure ay naglalaman ng error. Ang pattern matching sa pamamagitan ng switch ay kumukuha ng kaugnay na mga halaga at nagpoproseso ng bawat kaso. Sinusuri ng compiler ang pagkakumpleto (exhaustive switch) — inaalis nito ang mga nakalimutang estado.
enum NetworkResult<T> {
case loading
case success(T)
case failure(Error)
}
enum MediaFile {
case image(url: URL, width: Int, height: Int)
case video(url: URL, duration: Double)
case audio(url: URL, bitrate: Int)
}
func handle(_ result: NetworkResult<String>) {
switch result {
case .loading:
print("Naglo-load...")
case .success(let data):
print("Natanggap: \(data)")
case .failure(let error):
print("Error: \(error.localizedDescription)")
}
}
let file = MediaFile.video(url: URL(string: "https://example.com/video.mp4")!, duration: 120)
if case .video(let url, let duration) = file {
print("Video \(url) tagal \(duration)s")
}
Pinapayagan ng Swift ang pagdaragdag ng mga pamamaraan, kinakalkulang mga pag-aari at pagsunod sa protocol sa pamamagitan ng extension para sa enum. Hindi ito nangangailangan ng pagbabago sa orihinal na deklarasyon — ang code ay nananatiling malinis at modular. Ang mga pamamaraan sa extension ay maaaring gumana sa kaugnay na mga halaga, kalkulahin ang hinangong data at magpatupad ng lohika ng negosyo.
extension MediaFile {
var fileName: String {
switch self {
case .image(let url, _, _),
.video(let url, _),
.audio(let url, _):
return url.lastPathComponent
}
}
var description: String {
switch self {
case .image(_, let w, let h):
return "Larawan \(w)x\(h)"
case .video(_, let d):
return "Video \(d)s"
case .audio(_, let b):
return "Audio \(b) kbps"
}
}
}
extension MediaFile: Equatable {
static func == (lhs: MediaFile, rhs: MediaFile) -> Bool {
return lhs.fileName == rhs.fileName
}
}
let files: [MediaFile] = [file]
files.forEach { print($0.description) }
// "Video 120.0s"
Ang Enum na may kaugnay na mga halaga + extension ay ang kapalit para sa mga sealed class mula sa Kotlin o discriminated unions mula sa ibang mga wika. Ginagamit ng Swift ang kombinasyong ito para sa Result (isang standard na uri sa standard library), Optional (Optional ay isang enum na may .none at .some) at paghawak ng estado sa SwiftUI. Ginagarantiya ng pattern matching na ang lahat ng estado ay hinahawakan — imposible ang mga error sa runtime.
Mga Madalas Itanong
Struct — uri ng halaga, kinokopya sa pagtatalaga, hindi sumusuporta sa pamana. Class — uri ng sanggunian, ipinapasa sa pamamagitan ng sanggunian, sumusuporta sa pamana, deinit at pagsusuri ng pagkakakilanlan (===). Inirerekomenda ng Apple na magsimula sa struct at lumipat sa class lamang kapag kinakailangan ang semantika ng sanggunian.
Actor — uri ng sanggunian na ligtas sa thread. Pinipigilan ng compiler ang sabay-sabay na pag-access sa nababagong estado mula sa iba't ibang konteksto. Gamitin ang Actor para sa mga tagapamahala ng estado, cache at serbisyo na ina-access ng maraming gawain. Ang pagtawag sa mga pamamaraan ng actor ay nangangailangan ng await.
Pangunahin: @State — lokal na estado ng view; @Binding — koneksyon ng data nang walang pagmamay-ari; @Published — pag-publish ng mga pagbabago sa ObservableObject; @StateObject — pagmamay-ari ng ObservableObject; @EnvironmentObject — dependency mula sa kapaligiran. Ang mga custom na wrapper ay ginagawa sa pamamagitan ng @propertyWrapper.
POP — isang paradigm kung saan ang protocol + extension ay tumutukoy sa pag-uugali sa halip na pamana ng klase. Ang isang uri ay sumusunod sa maraming mga protocol, na nakakakuha ng kanilang mga implementasyon nang libre. Ito ay komposisyon sa halip na pamana — mas flexible at ligtas. Ang standard library ng Swift (Equatable, Codable) ay binuo sa POP.
Ang enum sa Swift ay sumusuporta sa kaugnay na mga halaga — bawat kaso ay maaaring mag-imbak ng arbitraryong data ng iba't ibang uri. Kapag pinagsama sa pattern matching (switch), nagbibigay ito ng isang makapangyarihang modelo para sa mga estado, error at Domain-Driven Design. Ang Optional at Result ay standard na Swift enum na may kaugnay na mga halaga.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.