WindowRootViewController
에 어떤 뷰컨이 놓여있는지 확인해야함(UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window?.rootViewController
var topViewController: UIViewController? {
return self.topViewController(currentViewController: self)
}
func topViewController(currentViewController: UIViewController) -> UIViewController {
if let tabBarController = currentViewController as? UITabBarController,
let selectedViewController = tabBarController.selectedViewController {
return self.topViewController(currentViewController: selectedViewController)
} else if let navigationController = currentViewController as? UINavigationController,
let visibleViewController = navigationController.visibleViewController {
return self.topViewController(currentViewController: visibleViewController)
} else if let presentedViewController = currentViewController.presentedViewController {
return self.topViewController(currentViewController: presentedViewController)
} else {
return currentViewController
}
}
guard let rootViewController = (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window?.rootViewController?.topViewController else {return}
if rootViewController is SnapDetailViewController {
rootViewController.present(DetailViewController(), animated: true, completion: nil)
}
guard let rootViewController = (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window?.rootViewController?.topViewController else {return}
if rootViewController is DetailViewController {
completionHandler([])
} else {
completionHandler([.list, .badge, .sound, .banner])
}
func sceneWillEnterForeground(_ scene: UIScene) {
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
UNUserNotificationCenter.current().removeAllDeliveredNotifications() // local, push 모두 해당
UIApplication.shared.applicationIconBadgeNumber = 0
}
아래와 같은 JSON 형식의 문자열이 있을 때
let json = """
{
"quote": "Your body is made to move so move it.",
"author": "Toni Sorenson"
}
"""
JSON 구조와 동일하게 구조체를 구성해주고 이로 변환할 때 Decoding을 사용할 수 있다. 이때 JSON key와 Struct의 변수명이 동일해야함!
struct Quote: Decodable {
var quote: String
var author: String
}
디코드를 하기 위해서는 Data 타입이 필요하기 때문에 현재 JSON형식으로 구성된 String을 utf8로 인코딩하여 Data로 변환시켜준다.
guard let result = json.data(using: .utf8) else { fatalError("Failed") }
그 후 JSONDecoder()를 사용하여 Data타입을 JSON으로 변환시켜준다. 이때 JSONDecoder의 특성을 설정해줄 수 있다.
let decoder = JSONDecoder()
//decoder.keyDecodingStrategy = .convertFromSnakeCase
do {
let value = try decoder.decode(Quote.self, from: result)
print(value)
} catch {
print(error)
}
.convertFromSnakeCase
를 사용하면 아래와 같이 JSON Key와 Struct의 프로퍼티명이 snake case, Camel case로 다를 때 CodingKey를 따로 추가하지 않고 변환시켜줄 수 있다.let json = """
{
"quote_content": "Your body is made to move so move it.",
"author_name": "Toni Sorenson"
}
"""
struct Quote: Decodable {
var quoteContent: String
var authorName: String
}
CodingKeys
를 사용하면 된다.let json = """
{
"quote_content": "Your body is made to move so move it.",
"author_name": "Toni Sorenson"
}
"""
struct Quote: Decodable {
var quote: String
var author: String
// 인코딩, 디코딩할때 사용할 키를 정의할 수 있음
enum CodingKeys: String, CodingKey {
case quote = "quote_content"
case author = "author_name"
}
}
다음과 같은 JSON 형식의 문자열이 있다.
let json = """
{
"quote_content": "Your body is made to move so move it.",
"author": null,
"like_count": 12345
}
"""
이때 author의 값이 null 인 경우에는 "작자미상"이라는 데이터를 보여주고 like_count값이 10000이 넘는 경우에는 influencer에 true라는 값을 주고싶다면?
init(from decoder: Decoder) throws
초기화 구문을 통해 초기화 시켜주기let container = try decoder.container(keyedBy: CodingKeys.self)
Returns the data stored in this decoder as represented in a container keyed by the given key type.
struct Quote: Decodable {
let quote: String
let author: String?
let like: Int
let influencer: Bool
enum CodingKeys: String, CodingKey {
case quote = "quote_content"
case author
case like = "like_count"
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
quote = try container.decode(String.self, forKey: .quote)
author = (try? container.decodeIfPresent(String.self, forKey: .author)) ?? "작자미상"
like = try container.decode(Int.self, forKey: .like)
influencer = (10000...).contains(like) ? true : false
}
}
guard let jsonData = json.data(using: .utf8) else { fatalError("Failed") }
do {
let value = try JSONDecoder().decode(Quote.self, from: jsonData)
dump(value)
} catch {
print(error)
}
struct User: Encodable {
var name: String
var signUpDate: Date
var age: Int
}
let users: [User] = [
User(name: "Jack", signUpDate: Date(), age: 33),
User(name: "Elsa", signUpDate: Date(timeInterval: -86400, since: Date()), age: 18),
User(name: "Emily", signUpDate: Date(timeIntervalSinceNow: 86400 * 2), age: 11),
]
let encode = JSONEncoder()
encode.outputFormatting = .prettyPrinted
encode.dateEncodingStrategy = .iso8601 // (iso 국제표준화기구)
do {
let jsonData = try encode.encode(users)
guard let jsonString = String(data: jsonData, encoding: .utf8) else { fatalError("Failed") }
print(jsonString)
} catch {
print(error)
}
let format = DateFormatter()
format.locale = Locale(identifier: "ko_KR")
format.dateFormat = "yyyy년 MM월 dd일 EEEE"
encode.dateEncodingStrategy = .formatted(format)
do {
let value = try JSONDecoder().decode(Quote.self, from: result)
print(value)
} catch {
print(error)
}
위의 코드에서 Quote.self
는 Meta Type이다.
Meta Type이란 클래스, 구조체, 열거형 등의 유형 자체를 일컫는 말이다.
let quote: Quote = Quote(quote: "명언", author: "혜")
이때 quote의 타입은 Quote(구조체)
이다. 이는 인스턴스에 대한 타입인 것 이다. 그럼 구조체 Quote의 타입은 무엇일까? 그 타입은 Quote.Type
으로 이때 메타타입이 언급되게 되는 것이다!
동일하게 let name: String = "린"
에서 name은 String이기 때문에 name의 타입은 String.Type
이 되는 것 이다.
이때 구조체 User를 살펴보면 identifier는 타입 프로퍼티이다. User의 인스턴스인 currentUser에서는 name에만 접근이 가능하고 identifier에만 접근이 가능한데 그 이유는 타입 프로퍼티는 User라는 구조체 타입 자체에서만 접근이 가능하기 때문이다.
struct User {
var name = "고래밥"
static let identifier = 1234567 // 타입 프로퍼티
}
let currentUser = User()
User.identifier
User.self.identifier
type(of: user).identifier