Singleton — шта је то, појединачна инстанца класе у iOS и Android

Аутор: IT Sectr Објављено: 2026-02-17 Време читања: 8 мин

Singleton — градивни образац који гарантује јединствену инстанцу класе и пружа глобалну тачку приступа њој. Singleton се широко користи у мобилном развоју за дељене ресурсе: мрежни клијенти, базе података, менаџери подешавања. Образац је описан у класичној књизи GoF (1994) и остаје један од најпрепознатљивијих. Детаљније — на Refactoring Guru: Singleton.

Главно

  • Singleton — гарантује једну инстанцу класе у целој апликацији
  • Глобална тачка приступа — статичко својство shared или companion object
  • Thread safety — захтева синхронизацију за исправан рад у вишенитном окружењу
  • Критика — Singleton отежава тестирање и ствара скривене зависности
  • Алтернативе — Dependency Injection, Service Locator за замену Singleton

Шта је Singleton: суштина синглтон обрасца?

Singleton — градивни образац који је описао GoF (Gang of Four) 1994. године. Образац решава два задатка: ограничава стварање инстанце класе на један објекат и пружа глобални приступ том објекту. Singleton је користан за ресурсе који морају бити јединствени: фабрика сесија, кеш слика, менаџер повезивања са базом података, Crashlytics или Analytics клијент.

Имплементација Singleton захтева приватни конструктор (забрањује спољно стварање), статичко поље са јединственом инстанцом и статички метод приступа (shared, instance, getInstance). Клијенти позивају Singleton.shared.method() без бриге о стварању објекта. Образац је популаран у iOS и Android: URLSession.shared, UserDefaults.standard, FirebaseApp.sharedInstance — све су то Singleton. Међутим, прекомерна употреба Singleton води до антиобрасца Global State.

Проблеми Singleton — скривене зависности (класе имплицитно зависе од Singleton објекта), тешкоћа тестирања (не може се заменити инстанца у тесту без додатног напора), кршење Single Responsibility Principle (Singleton управља и својом инстанцом и пословном логиком). Савремени мобилни развој преферира DI (Dagger, Hilt, Swinject) за управљање јединственим инстанцама — DI контејнер ствара објекат једном и убризгава га кроз конструктор.

Singleton у iOS на Swift: shared и статичка својства

Swift Singleton се имплементира кроз статичко својство shared са приватним иницијализатором. Од Swift 3, лења иницијализација статичких својстава је гарантовано нитно безбедна — компајлер аутоматски додаје синхронизацију кроз dispatch_once. Довољно је декларисати static let shared = Class() и учинити init() приватим. Swift не захтева додатну синхронизацију за једнонитни приступ након иницијализације.

swift
final class NetworkManager {
    // Thread-safe Singleton
    static let shared = NetworkManager()

    private init() {
        URLSessionConfiguration.default.timeoutIntervalForRequest = 30
    }

    private var cache = NSCache<NSString, NSData>()

    func fetchData(from url: URL) async throws -> Data {
        let key = url.absoluteString as NSString
        if let cached = cache.object(forKey: key) {
            return cached as Data
        }
        let (data, _) = try await URLSession.shared.data(from: url)
        cache.setObject(data as NSData, forKey: key)
        return data
    }
}

// Коришћење
let data = try await NetworkManager.shared.fetchData(from: url)

Apple Singleton — у iOS SDK многи објекти користе Singleton: UIApplication.shared, UIScreen.main, FileManager.default, NotificationCenter.default, UserDefaults.standard. Apple користи Singleton за услуге које су физички јединствене (један екран, једна апликација). Програмери копирају овај образац за своје услуге. У SwiftUI глобални приступ Singleton-у се замењује Environment и @EnvironmentObject, што побољшава тестирабилност.

Singleton у Android на Kotlin: companion object и object

Kotlin Singleton — најједноставнији начин: кључна реч object декларише класу-синглтон са лењом иницијализацијом при првом приступу. Kotlin object је нитно безбедан и не захтева додатну синхронизацију. Ако је потребан Singleton са параметрима конструктора, користи се companion object са lazy делегатом. У Android-у Singleton је често неопходан за Application контекст и услуге које се иницијализују кроз Application.onCreate().

kotlin
// Варијанта 1: object — једноставан Singleton без параметара
object AppPreferences {
    private val prefs = Application.instance
        .getSharedPreferences("app", Context.MODE_PRIVATE)

    var isFirstLaunch: Boolean
        get() = prefs.getBoolean("first_launch", true)
        set(value) = prefs.edit { putBoolean("first_launch", value) }
}

// Варијанта 2: companion object — Singleton са параметрима
class ApiClient private constructor(baseUrl: String) {
    companion object {
        @Volatile
        private var instance: ApiClient? = null

        fun getInstance(baseUrl: String): ApiClient {
            return instance ?: this.synchronized {
                instance ?: ApiClient(baseUrl).also { instance = it }
            }
        }
    }

    fun request(endpoint: String): String { /* ... */ }
}

Android SDK Singleton — многи системски сервиси Android-а имплементирају Singleton: context.getSystemService(), Room.databaseBuilder(), Retrofit.Builder(). Примери укључују SharedPreferences, MediaPlayer, AudioManager. У Android апликацијама Singleton се често користи за репозиторијуме, менаџере и фабрике. Google препоручује замену Singleton-а са DI (Hilt, Koin), где Singleton опсег (Scope.Singleton или @Singleton) управља контејнер, а класа остаје тестирабилна.

Thread safety: dispatch_once, synchronized и lock

Thread safety — критичан захтев за Singleton у вишенитном окружењу. Без синхронизације две нити могу истовремено проверити instance == null и створити две инстанце. Решење — блокирање при првом стварању и отпуштање након иницијализације. У Swift-у статичка својства (static let) су подразумевано нитно безбедна. У Kotlin-у object је нитно безбедан. За Java стил у Kotlin-у се користи synchronized или @Volatile + double-check locking.

ЈезикМеханизамНитна безбедностЛења иницијализација
Swiftstatic letdispatch_once (ауто)Да, при првом приступу
Kotlin objectObject declarationИницијализатор класе је нитно безбеданДа, при првом приступу
Kotlin companionsynchronized + @VolatileDouble-checked lockingДа, кроз lazy или synchronized
Javasynchronized + volatileDouble-checked lockingДа, у getInstance()

Double-checked locking — образац за лењу иницијализацију Singleton. Прва провера без синхронизације (брза, ако инстанца већ постоји), друга — унутар synchronized (стварање само једном нити). @Volatile гарантује видљивост промена за све нити. Без volatile друга нити може видети делимично створен објекат. У Kotlin-у lazy делегат са LazyThreadSafetyMode.SYNCHRONIZED аутоматски имплементира double-checked locking.

Singleton vs Dependency Injection: када користити

Dependency Injection — алтернатива Singleton-у за управљање јединственом инстанцом. DI контејнер (Dagger, Hilt, Koin, Swinject) ствара објекат једном у Singleton опсегу и убризгава га кроз конструктор. Класа не зна за свој Singleton статус — то одлучује контејнер. Код постаје тестирабилан: у тесту DI модул се замењује mock модулом. Предности DI: експлицитне зависности у конструктору, могућност преоптерећења, јединствени животни циклус.

Када је Singleton оправдан — објекти системског нивоа: Crashlytics, Analytics, Logging. Ове услуге се иницијализују једном у AppDelegate/Application и користе се свуда. DI је за њих претерано. Singleton је такође погодан за кешове слика (NSCache, Coil, Glide), где је глобални приступ оправдан перформансама. За све остало DI је пожељнији: чини зависности видљивим, поједностављује тестирање и рефакторисање.

Хибридни приступ — Singleton са могућношћу преоптерећења за тестове. У Swift-у се користи протокол + статичко својство које тест може заменити (нпр. кроз URLProtocol за URLSession). У Kotlin-у — open класа са injectable својством, где тест поставља mock кроз рефлексију или setter. Овај приступ задржава једноставност Singleton-а, али пружа алате за тестирање. Google препоручује Hilt за Android, Apple не намеће DI за iOS — избор зависи од тима.

Често постављана питања

Singleton — да ли је антиобразац?

Не, Singleton је GoF образац, али његова честа неправилна употреба претвара га у антиобразац Global State. Singleton је оправдан за физички јединствене ресурсе (екран, штампач, фајл систем). Проблеми настају када се Singleton користи за управљање подацима: скривене зависности, тешкоћа тестирања, кршење Single Responsibility Principle. Савремена алтернатива — DI са Singleton опсегом.

Како тестирати код који користи Singleton?

Три приступа: (1) кроз протокол — Singleton имплементира протокол, тестови замењују имплементацију; (2) кроз DI — Singleton се убризгава као зависност кроз конструктор; (3) кроз reset метод — Singleton има метод за ресетовање стања у тестовима (само за тест билд). Први приступ је пожељнији, трећи — опасан за production. Swift омогућава замену shared својства кроз runtime манипулације у тестовима.

По чему се Kotlin object разликује од Java Singleton?

Kotlin object — језичка конструкција која ствара Singleton на нивоу бајткода. За разлику од Java имплементације са приватим конструктором и getInstance(), object гарантује нитну безбедност, лењу иницијализацију и забрану наслеђивања. Java Singleton захтева ручну синхронизацију (synchronized) и volatile за исправан рад у вишенитном окружењу. Kotlin object — најбезбеднији и најконцизнији начин у Android-у.

Може ли се Singleton наследити?

Наслеђивање Singleton крши образац: ако се Singleton класа може наследити, подкласа може створити другу инстанцу, нарушавајући јединственост. У Swift-у final class забрањује наслеђивање. Kotlin object не може бити наследјен (object — sealed). Ако је потребан Singleton са варијабилношћу, користите DI контејнер са Singleton опсегом: гарантује једну инстанцу и подржава наслеђивање кроз интерфејсе.

Како проследити параметре у Singleton у Android-у?

Параметри се прослеђују кроз init(context: Application) или getInstance(param). Kotlin object не прихвата параметре — користите companion object са фабричким методом getInstance(param). Hilt решава проблем: @Singleton + @Inject constructor(context: Application) — DI контејнер убризгава Application контекст аутоматски. За retrofit клијент параметри (baseUrl, interceptors) се прослеђују кроз builder у DI модулу.

Завршни

  • Singleton — образац са јединственом инстанцом и глобалним приступом
  • Swift shared — static let са нитном безбедношћу од компајлера
  • Kotlin object — лења иницијализација без додатног кода
  • Thread safety — double-checked locking за Java, аутоматски за Swift/Kotlin
  • Apple SDK — UIApplication.shared, UserDefaults.standard, FileManager.default
  • Android SDK — Retrofit, Room, SharedPreferences кроз Singleton менаџере
  • Алтернативе — Dependency Injection за тестирабилан код

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође