1. 첫 번째 학습 내용: 싱글턴 (Singleton)

A singleton class returns the same instance no matter how many times an application requests it. A typical class permits callers to create as many instances of the class as they want, whereas with a singleton class, there can be only one instance of the class per process. A singleton object provides a global point of access to the resources of its class. Singletons are used in situations where this single point of control is desirable, such as with classes that offer some general service or resource.

싱글턴은 '특정 클래스의 인스턴스가 오직 하나임을 보장하는 객체'를 의미합니다. 싱글턴은 애플리케이션이 요청한 횟수와는 관계없이 이미 생성된 같은 인스턴스를 반환합니다. 즉, 애플리케이션 내에서 특정 클래스의 인스턴스가 딱 하나만 있기 때문에 다른 인스턴스들이 공유해서 사용할 수 있습니다.

You obtain the global instance from a singleton class through a factory method. The class lazily creates its sole instance the first time it is requested and thereafter ensures that no other instance can be created. A singleton class also prevents callers from copying, retaining, or releasing the instance. You may create your own singleton classes if you find the need for them. For example, if you have a class that provides sounds to other objects in an application, you might make it a singleton.

Cocoa 프레임워크에서의 싱글턴 디자인 패턴

Cocoa 프레임워크에서 싱글턴 디자인 패턴을 활용하는 대표적인 클래스를 소개합니다. 싱글턴 인스턴스를 반환하는 팩토리 메서드나 프로퍼티는 일반적으로 shared라는 이름을 사용합니다.

  • [FileManager](https://developer.apple.com/documentation/foundation/filemanager)
    • 애플리케이션 파일 시스템을 관리하는 클래스입니다.
    • FileManager.default
  • [URLSession](https://developer.apple.com/documentation/foundation/urlsession)
    • URL 세션을 관리하는 클래스입니다.
    • URLSession.shared ⭐️
  • [NotificationCenter](https://developer.apple.com/documentation/foundation/notificationcenter)
    • 등록된 알림의 정보를 사용할 수 있게 해주는 클래스입니다.
    • NotificationCenter.default
  • [UserDefaults](https://developer.apple.com/documentation/foundation/userdefaults)
    • Key-Value 형태로 간단한 데이터를 저장하고 관리할 수 있는 인터페이스를 제공하는 데이터베이스 클래스입니다.
    • UserDefaults.standard
  • [UIApplication](https://developer.apple.com/documentation/uikit/uiapplication)
    • iOS에서 실행되는 중앙제어 애플리케이션 객체입니다.
    • UIApplication.shared

주의할 점

싱글턴 디자인 패턴은 애플리케이션 내의 특정 클래스의 인스턴스가 하나만 존재하기 때문에 객체가 불필요하게 여러 개 만들어질 필요가 없는 경우에 많이 사용합니다. 예를 들면 환경설정, 네트워크 연결처리, 데이터 관리 등등이 있습니다. 하지만 멀티 스레드 환경에서 동시에 싱글턴 객체를 참조할 경우 원치 않은 결과를 가져올 수 있습니다.

출처: 부스트코스 iOS 앱 프로그래밍

Article

Managing a Shared Resource Using a Singleton

You use singletons to provide a globally accessible, shared instance of a class. You can create your own singletons as a way to provide a unified access point to a resource or service that’s shared across an app, like an audio channel to play sound effects or a network manager to make HTTP requests.

Create a Singleton

You create simple singletons using a static type property, which is guaranteed to be lazily initialized only once, even when accessed across multiple threads simultaneously:

If you need to perform additional setup beyond initialization, you can assign the result of the invocation of a closure to the global constant:

class Singleton {
    static let sharedInstance: Singleton = {
        let instance = Singleton()
        // setup code
        return instance
    }()
}

Apple Developer Documentation

2. 두 번째 학습 내용: Trailing Closures (후행 클로저)

If you need to pass a closure expression to a function as the function’s final argument and the closure expression is long, it can be useful to write it as a trailing closure instead.

You write a trailing closure after the function call’s parentheses, even though the trailing closure is still an argument to the function. When you use the trailing closure syntax, you don’t write the argument label for the first closure as part of the function call. A function call can include multiple trailing closures; however, the first few examples below use a single trailing closure.

let digitNames = [
    0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",
    5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]

let strings = numbers.map { (number) -> String in
    var number = number
    var output = ""
    repeat {
        output = digitNames[number % 10]! + output
        number /= 10
    } while number > 0
    return output
}
// strings is inferred to be of type [String]
// its value is ["OneSix", "FiveEight", "FiveOneZero"]

참고)

고차함수 map

Sunny - TIL - 210423

3. 세 번째 학습 내용: Type Casting

Type casting is a way to check the type of an instance, or to treat that instance as a different superclass or subclass from somewhere else in its own class hierarchy.

Type casting in Swift is implemented with the is and as operators. These two operators provide a simple and expressive way to check the type of a value or cast a value to a different type.

Downcasting

A constant or variable of a certain class type may actually refer to an instance of a subclass behind the scenes. Where you believe this is the case, you can try to downcast to the subclass type with a type cast operator (as? or as!).

  • Use the conditional form of the type cast operator (as?) when you aren’t sure if the downcast will succeed. This form of the operator will always return an optional value, and the value will be nil if the downcast was not possible. This enables you to check for a successful downcast.
  • Use the forced form of the type cast operator (as!) only when you are sure that the downcast will always succeed. This form of the operator will trigger a runtime error if you try to downcast to an incorrect class type.

In this example, each item in the array might be a Movie, or it might be a Song. You don’t know in advance which actual class to use for each item, and so it’s appropriate to use the conditional form of the type cast operator (as?) to check the downcast each time through the loop:

import Cocoa

class MediaItem {
    var name: String
    init(name: String) {
        self.name = name
    }
}

class Movie: MediaItem {
    var director: String
    init(name: String, director: String) {
        self.director = director
        super.init(name: name)
    }
}

class Song: MediaItem {
    var artist: String
    init(name: String, artist: String) {
        self.artist = artist
        super.init(name: name)
    }
}

let library = [
    Movie(name: "컨저링 3: 악마가 시켰다", director: "마이클 차베즈 (Michael Chaves)"),
    Song(name: "Butter", artist: "BTS (방탄소년단)"),
    Movie(name: "크루엘라", director: "크레이그 질레스피"),
    Song(name: "라미란이 (RAMIRANI)", artist: "라미란, 미란이 (Ra Mi Ran, Mirani)"),
    Song(name: "Alcohol-Free", artist: "TWICE")
]
// the type of "library" is inferred to be [MediaItem]

for item in library {
    if let movie = item as? Movie {
        print("Movie: \(movie.name), dir. \(movie.director)")
    } else if let song = item as? Song {
        print("Song: \(song.name), by \(song.artist)")
    }
}

// Movie: 컨저링 3: 악마가 시켰다, dir. 마이클 차베즈 (Michael Chaves)
// Song: Butter, by BTS (방탄소년단)
// Movie: 크루엘라, dir. 크레이그 질레스피
// Song: 라미란이 (RAMIRANI), by 라미란, 미란이 (Ra Mi Ran, Mirani)
// Song: Alcohol-Free, by TWICE

The example starts by trying to downcast the current item as a Movie. Because item is a MediaItem instance, it’s possible that it might be a Movie; equally, it’s also possible that it might be a Song, or even just a base MediaItem. Because of this uncertainty, the as? form of the type cast operator returns an optional value when attempting to downcast to a subclass type. The result of item as? Movie is of type Movie?, or “optional Movie”.

This optional binding is written “if let movie = item as? Movie”, which can be read as:

“Try to access item as a Movie. If this is successful, set a new temporary constant called movieto the value stored in the returned optional Movie.”

Casting doesn’t actually modify the instance or change its values. The underlying instance remains the same; it’s simply treated and accessed as an instance of the type to which it has been cast.

profile
iOS Developer

0개의 댓글