Untitled

mail@pastecode.io avatar
unknown
swift
2 years ago
3.5 kB
0
Indexable
Never
import UIKit

let semaphore = DispatchSemaphore(value: 1)

// Класс одиночки определяет статический метод `getInstance`,
// который позволяет повторно использовать одно и то же
// подключение к APIClient по всей программе.
class APIClient {
    // Конструктор одиночки всегда должен оставаться приватным,
    // чтобы мы не смогли самостоятельно создавать
    // экземпляры этого класса через оператор `new`.
    private init() {}
    
    // Поле для хранения объекта-одиночки должно быть объявлено статичным.
    // Восклицательный знак означает, что мы гарантируем, что поле не будет nil,
    // даже при учете того, что оно не задано в инициализаторе.
    private static var shared: APIClient!
    
    // Основной статический метод одиночки служит альтернативой
    // конструктору и является точкой доступа к экземпляру этого
    // класса.
    static func getInstance() -> APIClient {
        if shared == nil {
            // Заставим остальные потоки дождаться создания объекта
            semaphore.wait()
            // На всякий случай ещё раз проверим, не был ли
            // объект создан другим потоком, пока текущий
            // ждал освобождения блокировки.
            if shared == nil {
                shared = APIClient()
            }
        }
        // Разрешим остальным потокам продолжить выполнение
        semaphore.signal()
        return shared
    }
    
    // Предоставляемый функционал
    func makeRequest() {
        APIClientLogic.makeRequest()
    }
    
    // Создание еще одного приватного класса обусловлено
    // стремлением следовать Single Responsibility Principle.
    // В итоге первый класс отвечает за обеспечение единственного экземпляра,
    // второй выполняет непосредственную задачу апи клиента.
    // ВАЖНО: Доступа к APIClientLogic ни у кого нет. Все методы в нем статичны. Никто не сможет создать
    // экземпляр APIClient, но на всякий случай даже у него мы скрываем инициализатор.
    private class APIClientLogic {
        private init() {}
        static func makeRequest() {
            /*...*/
        }
    }
    
}

// По умолчанию для каждого класса Swift предоставляет возможность использовать метод copy,
// создающий новый объект класса.
// Переопределим метод, запретив копирование объекта.
extension APIClient: NSCopying {
    func copy(with zone: NSZone? = nil) -> Any {
            return self
        }
}