let dateComponents = DateComponents(year: year, quarter: quarter)
let calendar = Calendar.current
let date = calendar.date(from: dateComponents)
[카테고리:] API
iOS DateFormatter using User’s OS Language Setting is Korean or English
Korea | English(US) | English(KR) | joined(USA) | |
yyyyQQQ | 2023년 1분기 | Q1 2023 | ||
yyyyQQQQ | 2023년 제 2/4분기 | 2nd quarter 2023 | ||
yyyyMMM | 2023년 2월 | Feb 2023 | ||
yyyyMMMM | 2023년 4월 | April 2023 | ||
yyyy | 2023년 | 2023 | ||
M | 2월 | 2 | ||
d | 6일 | 6 | ||
yyMMdd HH:mm | 23. 02. 06. 22:44 | 02/06/23, 01:01 | 23/01/01 1:01 | |
yyMd | 23. 2. 6. | 2/6/23 | 23/02/06 | |
MMMMd | 2월 10일 | April 21 | ||
MMMd | 2월 10일 | Fed 10 | ||
Md | 2. 6. | 2/6 | ||
HH:mm | 01:01 | 01:01 | 1:01 | |
date full | 2023년 2월 6일 월요일 | Monday, February 6, 2023 | February 6, 2023 at 11:00:09 AM Korean Standard Time | |
date long | 2023년 2월 6일 | February 6, 2023 | February 6, 2023 at 11:00:09 AM GMT+9 Monday | |
date medium | 2023. 2. 6. | Feb 6, 2023 | Feb 6, 2023 at 11:00:09 AM | |
date short | 2023. 2. 6. | 2/6/23 | 2/6/23, 11:00 AM | |
time full | 오전 10시 57분 25초 대한민국 표준시 | 11:00:09 AM Korean Standard Time | ||
time long | 10시 48분 59초 GMT+9 | 11:00:09 AM GMT+9 | ||
time medium | 10:48:59 | 11:00:09 AM | ||
time short | 오전 1:01 / 01:01 | 1:01 AM / 01:01 | 1:01 AM / 1:01 |
// OS 24 format on
2023. 2. 6. //short
2023. 2. 6. //medium
2023년 2월 6일 //long
2023년 2월 6일 월요일 //full
2023. 2. 6. 10:48 //short
2023. 2. 6. 10:48:59 //medium
2023년 2월 6일 10시 48분 59초 GMT+9 //long
2023년 2월 6일 월요일 10시 48분 59초 대한민국 표준시 //full
// OS 24 Hour off
2023. 2. 6.
2023. 2. 6.
2023년 2월 6일
2023년 2월 6일 월요일
2023. 2. 6. 오전 10:57
2023. 2. 6. 오전 10:57:25
2023년 2월 6일 오전 10시 57분 25초 GMT+9
2023년 2월 6일 월요일 오전 10시 57분 25초 대한민국 표준시
// English
2/6/23
Feb 6, 2023
February 6, 2023
Monday, February 6, 2023
2/6/23, 11:00 AM
Feb 6, 2023 at 11:00:09 AM
February 6, 2023 at 11:00:09 AM GMT+9
Monday, February 6, 2023 at 11:00:09 AM Korean Standard Time
//at is when the date style is medium or full. "," instead for short
DateStyle
short 2023. 2. 6. 2/6/23
medium 2023. 2. 6. Feb 6, 2023
long 2023년 2월 6일 February 6, 2023
full 2023년 2월 6일 월요일 Monday, February 6, 2023
TimeStyle
short 10:48 11:00 AM
medium 10:48:59 11:00:09 AM
long 10시 48분 59초 GMT+9 11:00:09 AM GMT+9
full 10시 48분 59초 대한민국 표준시 11:00:09 AM Korean Standard Time
"MMM d HH:mm a"
1월 31 15:00 오후
Feb 3 12:40 PM
If you want to use without year but localized
formatter1.setLocalizedDateFormatFromTemplate("MMMd") //1월 31일 / Feb 3
If you do not use setLocalizedDateFormatFromTemplate it will be like “1월 31” in Korean.
formatter1.dateFormat = "MMM dd"
Other format if you use setLocalizedDateFormatFromTemplate
"yyyy. MM. dd", 12/28/2022 2022. 12. 28.
"yyMMdd" 02/06/2023 23. 02. 06.
"yyyy MMM", Dec 2022 2022년 12월
"MMM dd", Dec 28 12월 28일
"MMMd", Dec 28 12월 28일
"M.d", 12/28 12. 28. 4. 7. 12/28(USA)
"MM.dd", 12/28 12. 28. 04. 07.
"MMdd" 12/28 12. 28. 04. 07.
"hh:mm" 12:03 PM 오후 12:03
"HH:mm" 12:03 12:03
You can test with this code
let today = Date.now
let december = Date(timeIntervalSince1970: 1680642800)
let formatter1 = DateFormatter()
//dateFormatter.locale = Locale(identifier: "en_US_POSIX")
let koreaFormatter = DateFormatter()
koreaFormatter.locale = Locale(identifier: "ko_KR")
let englishUSFormatter = DateFormatter()
englishUSFormatter.locale = Locale(identifier: "en_US")
let englishKoreaFormatter = DateFormatter()
englishKoreaFormatter.locale = Locale(identifier: "en_KR")
let formatters = [koreaFormatter, englishUSFormatter, englishKoreaFormatter]
for formatter1 in formatters {
for today in [december] {
// formatter1.doesRelativeDateFormatting = true
formatter1.dateStyle = .short
print(formatter1.string(from: today))
print("dateStyle short \(formatter1.string(from: today))")
formatter1.dateStyle = .medium
print("dateStyle medium \(formatter1.string(from: today))")
formatter1.dateStyle = .long
print("dateStyle long \(formatter1.string(from: today))")
formatter1.dateStyle = .full
print("dateStyle full \(formatter1.string(from: today))")
formatter1.dateStyle = .short
formatter1.timeStyle = .short
print("dateStyle short timeStyle short \(formatter1.string(from: today))")
formatter1.dateStyle = .medium
formatter1.timeStyle = .medium
print("dateStyle medium timeStyle medium \(formatter1.string(from: today))")
formatter1.dateStyle = .long
formatter1.timeStyle = .long
print("dateStyle long timeStyle long \(formatter1.string(from: today))")
formatter1.dateStyle = .full
formatter1.timeStyle = .full
print("dateStyle full timeStyle full \(formatter1.string(from: today))")
formatter1.dateStyle = .short
formatter1.timeStyle = .full
print("dateStyle short timeStyle full \(formatter1.string(from: today))")
for format in ["yyyy. MM. dd", "yyMMdd","yyMd", "yyyyMMM", "yyyyMMMM", "MMM dd", "MMMd", "MMMMd", "M.d", "MM.dd", "MMdd", "Md", "HH:mm", "H:m", "M", "d", "Q", "QQ", "QQQ", "YYYYQQQQ", "MMMdEEEE", "MMMdEEE"] {
formatter1.setLocalizedDateFormatFromTemplate(format)
formatter1.doesRelativeDateFormatting = true
// formatter1.dateFormat = format
print("\(format) \(formatter1.string(from: today))")
}
print("-----------")
}
}
let formatter = DateFormatter()
formatter.setLocalizedDateFormatFromTemplate("yyMMdd")
print(formatter.string(from: today))
formatter.dateStyle = .none
formatter.timeStyle = .short
print(formatter.string(from: today))
format terms https://leeari95.tistory.com/30
AppDelegate function orders
- When launch
- didFinishLaunchingWithOptions
- launch screen
- applicationDidBecomeActive
- When exit app
- applicationWillResignActive
- applicationDidEnterBackground
- When reenter app
- applicationWillEnterForeground
- applicationDidBecomeActive
- When terminate
- applicationDidEnterBackground
- applicationWillTerminate
- foreground includes active, inactive
- not Running -> inactive(foreground) -> active(foreground) -> Inactive(foreground) -> background -> suspended -> not running
- AppDelegate’s lifecycle
- state
- Not Running
- Inactive(foreground but is not receiving events. An app usually stays in this state only briefly as it transitions to a different state.)
- Active(foreground)
- Background(The app is executing code but is not visible onscreen.)
- Suspended(background but is not executing code. The system moves apps to this state automatically and does not notify them before doing so. When a low-memory condition occurs, the system may purge suspended apps without notice to make more space for the foreground app)
- Not Running -Launch-> Inactive -> Active
- Active -> Inactive -> Background -> Suspend -> Not Running
- state
https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle
setNeedsLayout vs. setNeedsDisplay
setNeedsDisplay triggers draw() or display() during the next cycle(: redraw itself)
setNeedsLayout triggers layoutSubviews() during the next cycle(: relayout subviews)
mark deprecated variables in Swift
https://stackoverflow.com/a/39905400/7193843
@available(*, deprecated, message: "2020.03.19 이후 가이드에서 사용되지 않음") @objc class var secondary1: UIColor { @available(*, deprecated, message: "2020.03.19 이후 가이드에서 사용되지 않음") extension UIColor { }
You can use deprecated annotation on variables and also on extension block.
If you add the annotation to extension block, warnings appear on all properties declared in extension block.
KVO Observation
class testView: UIView { func setUpView() { self.contentWebView.scrollView.addObserver(self, forKeyPath: #keyPath(UIScrollView.contentSize), options: [.old, .new], context: nil) } override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {}
self: where the function observeValue is declared
It’s better to use block observing
https://developer.apple.com/documentation/swift/cocoa_design_patterns/using_key-value_observing_in_swift
because if keyPath is not applicable, compile fails. But If you use addObserver, compile succeeds and observeValue never executed.
AppDelegate applicationDidBecomeActive vs. first view controller’s viewDidLoad. Which is first?
Order
- first view controller’s viewDidLoad
- first view controller’s viewWillAppear
- AppDelegate applicationDidBecomeActive
Apple Sign In Q&A
- Can I disable “Hide My Email” option? -> No.
- When a user changed email of Apple Id, does user identifier or email value change?
- user identifier: doesn’t change
- email: it doesn’t give changed email value. nil.
- email of identityToken: also doesn’t exist
- Can I get email value whenever user login?
- email: email value only received when user sign up to the app at first.
- email of identityToken: first sign up, login. but not after user changed email of Apple Id
- But when user login again after he/she chose “stop using apple Id on this app” on Settings, what information can I get?
- At first sign in after “stop using apple Id on this app”, I can get email value too.
- But at this time, user can choose “Hide My Email”
- If the user had chosen “Hide My Email” before, and chose “Hide My Email”, the address of relay email is same.
- But if user chose different option between “Hide My Email” and “Show My Email”, the value of email changes.
- Can I know if the user chose “Hide My Email”?
- Yes. If the user chose “Hide My Email”, email value has format <unique-alphanumeric-string>@privaterelay.appleid.com.
- Can I test on simulator?
- Yes. You need to login in Settings.
Can I request alert authorization again?
Because the system saves the user’s response, calls to this method during subsequent launches do not prompt the user again.
Problems of concurrency programming
- https://subscription.packtpub.com/book/application_development/9781785886126/1/ch01lvl1sec09/possible-problems-in-concurrent-applications
- once you encounter a shared resource in a concurrent software, you have to be careful while accessing this resource especially if you are writing to it.
- Problems
- Race condition: It becomes a bug(예상과 다름) when events do not happen in the order the programmer intended. the system’s substantive behavior is dependent on the sequence or timing of other uncontrollable events
- Solutions: identify the critical section and make it accessible by only one thread at a time.
- Design: double check, especially after the long process and right before writing process
- locks in critical section
- methods
- NSLocks
- mutex
- semaphore
- Cautions: it can cause deadlocks when locks are in different parts and they are needed to be released to execute each other. It make threads wait for other threads to release the locks.
- -> use serial dispatch queues instead
- methods
- submitting blocks on serial dispatch queue
- using .barriers flag on concurrent queue
- Solutions: identify the critical section and make it accessible by only one thread at a time.
- Priority Inversion:
- Deadlocks:
- Race condition: It becomes a bug(예상과 다름) when events do not happen in the order the programmer intended. the system’s substantive behavior is dependent on the sequence or timing of other uncontrollable events
Reference: https://medium.com/swiftcairo/avoiding-race-conditions-in-swift-9ccef0ec0b26