Cache

  • 캐시를 사용하는 이유: 개발자는 캐시를 사용하여 계산 비용이 많이 들 수 있는 일시적인 데이터와 함께 자주 액세스하는 개체를 저장합니다. 이러한 객체를 재사용하면 해당 값을 다시 계산할 필요가 없기 때문에 성능상의 이점을 얻을 수 있습니다. 그러나 객체가 앱에 중요하지 않으며 메모리가 부족한 경우 삭제할 수 있습니다. 버려지면 필요할 때 값을 다시 계산해야 합니다.
  • 캐싱으로 인해 발생할수 있는 문제: 캐싱은 성능 측면에서 엄청난 이점을 제공할 수 있지만 캐싱이 제공하는 몇 가지 가능한 단점도 있습니다. 가장 중요한 것은 캐싱이 매우 많은 양의 메모리를 사용할 수 있다는 것입니다. 많은 대용량 데이터 객체를 캐시할 때 너무 많은 객체를 캐시하여 다른 앱을 위한 RAM이 남지 않을 수 있으며, 시스템은 RAM을 확보하기 위해 이 모든 데이터를 디스크에 쓸 때 중단됩니다.

NSCache

Cocoa는 캐시하려는 항목을 위한 편리한 저장 컨테이너로 NSCache 객체를 제공하는 동시에 위에서 논의한 메모리 관리 문제를 해결합니다. NSCache 클래스는 둘 다 키-값 쌍을 보유한다는 점에서 NSDictionary 클래스와 매우 유사합니다. 그러나 NSCache 객체는 "반응형 캐시"입니다. 즉, 메모리를 사용할 수 있는 경우 제공된 모든 데이터를 적극적으로 캐시합니다. 그러나 메모리가 부족하면 다른 응용 프로그램에 사용할 메모리를 확보하기 위해 일부 요소를 자동으로 버립니다. 나중에 이러한 폐기된 항목이 필요한 경우 해당 값을 다시 계산해야 합니다. NSCache는 캐시된 요소의 수를 제한하고 캐시에 있는 모든 요소의 총 비용을 제한하는 두 가지 유용한 "제한" 기능을 제공합니다.

  • 캐시가 가질 수 있는 요소의 수를 제한하려면 setCountLimit: 메소드를 호출하십시오. 예를 들어 countLimit이 10으로 설정된 캐시에 11개의 항목을 추가하려고 하면 캐시에서 요소 중 하나를 자동으로 삭제할 수 있습니다.
  • 캐시에 항목을 추가할 때 각 키-값 쌍과 연결할 비용 값을 지정할 수 있습니다. setTotalCostLimit: 메소드를 호출하여 캐시된 모든 객체의 비용 합계에 대한 최대값을 설정합니다. 따라서 totalCost를 totalCostLimit 이상으로 밀어 넣는 개체가 추가되면 캐시는 임계값 아래로 돌아가기 위해 일부 개체를 자동으로 제거할 수 있습니다. 이 제거 프로세스는 보장되지 않으므로 특정 동작을 달성하기 위해 비용 값을 조작하려고 하면 캐시 성능이 저하될 수 있습니다. 유용한 것이 없으면 비용으로 0을 전달하거나 비용을 전달할 필요가 없는 setObject:forKey: 메소드를 사용하십시오.
  • [참고] 카운트 한도와 총 비용 한도는 엄격하게 적용되지 않습니다. 즉, 캐시가 한도 중 하나를 초과하면 캐시의 구현 세부 정보에 따라 캐시의 일부 개체가 즉시, 나중에 또는 전혀 제거되지 않을 수 있습니다.

URLCache

참조

'' 카테고리의 다른 글

Sync/Async  (0) 2022.11.05
GCD/Operation  (0) 2022.11.05
setNeedsLayout() vs. setNeedsDisplay()  (0) 2022.11.03
LifeCycle  (0) 2022.10.28
언어 및 지역에 해당하는 문자열  (0) 2022.10.01

High Performance Auto Layout - WWDC18

setNeedsLayout

Main Run loop의 마지막 단계인 Update Cycle에 뷰의 레이아웃(size, position)을 업데이트하는 작업(layoutSubviews)을 예약한다. 명시적으로 호출해서 예약을 요청하는 것 또한 가능하며 다음과 같은 상황에서 자동으로 트리거된다.

  • 서브뷰를 추가할 경우
  • 뷰의 크기 변경될 경우
  • 스크롤이 발생할 경우
  • 디바이스가 회전될 경우

setNeedsDisplay

Main Run loop의 마지막 단계인 Update Cycle에 뷰의 display(text, color, image)를 업데이트하는 작업(draw)을 예약한다. 명시적으로 호출해서 예약을 요청하는 것 또한 가능하며 다음과 같은 상황에서 자동으로 트리거된다.

  • 뷰의 bounds가 변경될 경우

참조

'' 카테고리의 다른 글

GCD/Operation  (0) 2022.11.05
Cache  (0) 2022.11.04
LifeCycle  (0) 2022.10.28
언어 및 지역에 해당하는 문자열  (0) 2022.10.01
[해결방법] reason : The model used to open the store is incompatible with the one used to create the store  (0) 2021.12.25

디자인 패턴

디자인 패턴은 프로그래밍 과정에서 문제 해결을 위해 반복해서 경험하는 객체와 클래스의 관계를 정리한 것이다. 코코아 프레임워크 역시 여러 가지 상황에 대한 다양한 디자인 패턴이 적용되어 있다. 그 중에서도 객체의 역할에 따라 구분하는 MVC(모델-뷰-컨트롤러) 패턴에 대해 알아보자.

MVC

Model-View-Controller design pattern

모델

모델 객체는 화면을 구성하거나 내부 처리를 위한 데이터를 추상화해서 타입을 지정한 자료 구조로 표현하고, 데이터를 처리하는 로직을 정의한다. 앱에서 지속적으로 사용하는 데이터는 모델 객체 내부에 캡슐화되고, 파일이나 데이터베이스 같은 영구적인 구조로 저장하기도 한다.

MVC 패턴에서 데이터를 다루는 모델 객체는 화면을 구성하는 뷰 객체와 직접적으로 연결하지 않는다. 데이터에 접근하는 유일한 추상화 객체가 된다. 서버에서 받은 데이터 구조를 컨트롤러와 뷰에서 사용할 때 모델 객체가 기본 처리 단위가 된다.

뷰 객체는 코코아 프레임워크에서 대체로 UIView 클래스를 상속받아 앱 화면 자체를 그려서 표시하는 역할을 하고, 사용자 선택에 따라 입력을 받거나 피드백을 준다. 일반적으로 뷰 객체가 화면에 표시하는 정보는 모델 객체가 갖고 있는 데이터를 기반으로 한다. 하나의 뷰가 모델 하나와 매칭될 수도 있고, 하나의 뷰를 표현하기 위해서 여러 모델의 데이터가 필요하기도 한다. 반대로 하나의 모델의 데이터가 여러 뷰에서 사용자 입력에 따라 다르게 보여지기도 한다.

뷰 객체는 화면 구성을 위해서 모델 객체와 매우 밀접한 관계를 갖고 있지만, 이런 상호 관계를 끊고 느슨하게 결합하는 것이 MVC 패턴의 핵심 사항이다. 그 상호 관계를 유지하도록 도와주는 역할이 컨트롤러 객체의 역할이다. 따라서 컨트롤러가 연결해주는 모델 객체에 따라서 뷰 객체는 얼마든지 재사용이 가능하다.

컨트롤러

컨트롤러 객체는 뷰 객체와 모델 객체 사이에서 사용자 입력과 데이터 변화에 대한 연결을 해주는 중재자 역할을 한다. 사용자 입력에 따른 새로운 데이터 변화를 확인하고, 관련 모델에 새로운 데이터를 업데이트해준다. 반대로 모델에서 데이터가 바뀌면 뷰에 전달해서 새로운 데이터로 화면에 표시한다.

뷰 객체가 표시하는 화면 구조가 복잡하거나 사용자 입력 방식이 다양할수록 데이터 모델도 상대적으로 덩치가 크고 컨트롤러 객체의 동작이 복잡해진다.

MVC 패턴으로 구현할 때 가장 큰 고민거리는 컨트롤러 객체를 구현하는 코드가 복잡하고 길어진다는 것이다. 이전 화면이나 다음 화면으로 데이터를 전달하는 경우에는 각 화면을 담당하는 컨트롤러 사이에도 데이터를 전달해야 해서 더 복잡해진다. 따라서 가볍고 재사용성이 높은 컨트롤러 객체를 만들기 위해서 다양한 MVC 변형 패턴들을 함께 사용한다.

참조

' > Design Pattern' 카테고리의 다른 글

호출 패턴  (0) 2022.10.30
응답 체인 패턴 (UIResponder, Hit-Test)  (0) 2022.10.30
옵저버 패턴  (0) 2022.10.30
싱글턴 패턴  (0) 2022.10.30

ViewController LifeCycle

1. None

// FirstViewController가 보여지는 경우
FirstViewController viewDidLoad()
FirstViewController viewWillAppear(_:)
FirstViewController viewDidAppear(_:)

// FirstViewController -> SecondViewController으로 present
SecondViewController viewDidLoad()
SecondViewController viewWillAppear(_:)
SecondViewController viewDidAppear(_:)

// SecondViewController -> FirstViewController으로 dismiss
SecondViewController viewWillDisappear(_:)
SecondViewController viewDidDisappear(_:)
SecondViewController deinit

2. FullScreen

// FirstViewController가 보여지는 경우
FirstViewController viewDidLoad()
FirstViewController viewWillAppear(_:)
FirstViewController viewDidAppear(_:)

// FirstViewController -> SecondViewController으로 present
SecondViewController viewDidLoad()
FirstViewController viewWillDisappear(_:)
SecondViewController viewWillAppear(_:)
SecondViewController viewDidAppear(_:)
FirstViewController viewDidDisappear(_:)

// SecondViewController -> FirstViewController으로 dismiss
SecondViewController viewWillDisappear(_:)
FirstViewController viewWillAppear(_:)
FirstViewController viewDidAppear(_:)
SecondViewController viewDidDisappear(_:)
SecondViewController deinit

3. OverFullScreen

// FirstViewController가 보여지는 경우
FirstViewController viewDidLoad()
FirstViewController viewWillAppear(_:)
FirstViewController viewDidAppear(_:)

// FirstViewController -> SecondViewController으로 present
SecondViewController viewDidLoad()
SecondViewController viewWillAppear(_:)
SecondViewController viewDidAppear(_:)

// SecondViewController -> FirstViewController으로 dismiss
SecondViewController viewWillDisappear(_:)
SecondViewController viewDidDisappear(_:)
SecondViewController deinit

FullScreen vs. OverFullScreen

None FullScreen OverFullScreen
default fullScreen overFullScreen
  • UIModalPresentationFullScreen 스타일을 사용하여 뷰 컨트롤러를 표시할 때 UIKit은 일반적으로 전환 애니메이션이 완료된 후 기본 뷰 컨트롤러의 뷰를 제거
  • UIModalPresentationOverFullScreen 스타일을 지정하면 해당 보기의 제거를 방지할 수 있음
    (Presented 뷰 컨트롤러에 Presenting 뷰 컨트롤러의 콘텐츠가 표시되는 transparent 영역이 있는 경우 해당 스타일을 사용)

viewDidLoad vs. viewWillAppear

  • viewDidLoad
    • 뷰 컨트롤러가 뷰 계층 구조를 메모리에 로드한 후에 호출됨
    • nib파일에서 로드된 뷰에 대한 추가적인 초기화를 수행하거나 스토리보드에 없는 뷰를 추가하고 구성하기
  • viewWillAppear
    • 뷰 컨트롤러의 뷰가 뷰 계층에 추가되기 직전에 호출됨
    • 뷰 컨트롤러가 화면에 나타날 때마다 발생해야 하는 작업들을 수행하기
      • ex) 자동 재생이 활성화된 경우 미디어 파일 재생을 시작
      • ex) trailCollection 변경으로 인한 레이아웃 재설정

App LifeCycle

An illustration showing the state transitions for a scene-based app. Scenes start in the unattached state and move to the foreground-active or background state. The foreground-inactive state acts as a transition state.

// Unattached -> Foreground Inactive
AppDelegate application(_:didFinishLaunchingWithOptions:)
SceneDelegate scene(_:willConnectTo:options:)
FirstViewController viewDidLoad()
FirstViewController viewWillAppear(_:)
SceneDelegate sceneWillEnterForeground(_:) 

// Foreground Inactive -> Foreground Active
SceneDelegate sceneDidBecomeActive(_:)
FirstViewController viewDidAppear(_:)

// Foreground Active -> Foreground Inactive 
SceneDelegate sceneWillResignActive(_:)

// Foreground Inactive -> Foreground Active
SceneDelegate sceneDidBecomeActive(_:)

// Foreground Active -> (Foreground Inactive) -> Background
SceneDelegate sceneWillResignActive(_:)
SceneDelegate sceneDidEnterBackground(_:)

// Background -> (Foreground Inactive) -> Foreground Active
SceneDelegate sceneWillEnterForeground(_:)
SceneDelegate sceneDidBecomeActive(_:)
Foreground Inactive Foreground Active
Foreground Inactive Foreground Active
Foreground Inactive (App Switcher) Background
Foreground Inactive (App Switcher) Background
Foreground Active (incoming phone call) Background (incoming phone call)
Foreground Active (incoming phone call) Background (incoming phone call)
Foreground Inactive ↔ Active (Lock screen) Foreground Inactive (Lock screen)
Foreground Inactive ↔ Active (Lock screen) Foreground Inactive (Lock screen)
Foreground Inactive ↔ Active (Lock screen - camera) Background (Lock)
Foreground Inactive ↔ Active (Lock screen - camera) Background (Lock)

참고

+ Recent posts