iOS DateFormatter using User’s OS Language Setting is Korean or English

KoreaEnglish(US)English(KR)joined(USA)
yyyyQQQ2023년 1분기Q1 2023
yyyyQQQQ2023년 제 2/4분기2nd quarter 2023
yyyyMMM2023년 2월Feb 2023
yyyyMMMM2023년 4월April 2023
yyyy2023년2023
M2월2
d6일6
yyMMdd HH:mm23. 02. 06.  22:4402/06/23, 01:0123/01/01 1:01
yyMd23. 2. 6.2/6/2323/02/06
MMMMd2월 10일April 21
MMMd2월 10일Fed 10
Md2. 6.2/6
HH:mm01:0101:011:01
date full2023년 2월 6일 월요일Monday, February 6, 2023February 6, 2023 at 11:00:09 AM Korean Standard Time
date long2023년 2월 6일February 6, 2023February 6, 2023 at 11:00:09 AM GMT+9 Monday
date medium2023. 2. 6.Feb 6, 2023Feb 6, 2023 at 11:00:09 AM
date short2023. 2. 6.2/6/232/6/23, 11:00 AM
time full오전 10시 57분 25초 대한민국 표준시11:00:09 AM Korean Standard Time
time long10시 48분 59초 GMT+911:00:09 AM GMT+9
time medium10:48:5911:00:09 AM
time short오전 1:01 / 01:011:01 AM / 01:011: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

  1. When launch
    1. didFinishLaunchingWithOptions
    2. launch screen
    3. applicationDidBecomeActive
  2. When exit app
    1. applicationWillResignActive
    2. applicationDidEnterBackground
  3. When reenter app
    1. applicationWillEnterForeground
    2. applicationDidBecomeActive
  4. When terminate
    1. applicationDidEnterBackground
    2. applicationWillTerminate
  • foreground includes active, inactive
  • not Running -> inactive(foreground) -> active(foreground) -> Inactive(foreground) -> background -> suspended -> not running
  1. AppDelegate’s lifecycle
    1. state
      1. Not Running
      2. Inactive(foreground but is not receiving events. An app usually stays in this state only briefly as it transitions to a different state.)
      3. Active(foreground)
      4. Background(The app is executing code but is not visible onscreen.)
      5. 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)
      6. Not Running -Launch-> Inactive -> Active
      7. Active -> Inactive -> Background -> Suspend -> Not Running 

https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle

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.

Apple Sign In Q&A

  1. Can I disable “Hide My Email” option? -> No.
  2. When a user changed email of Apple Id, does user identifier or email value change?
    1. user identifier: doesn’t change
    2. email: it doesn’t give changed email value. nil.
    3. email of identityToken: also doesn’t exist 
  3. Can I get email value whenever user login?
    1. email: email value only received when user sign up to the app at first.
    2. email of identityToken: first sign up, login. but not after user changed email of Apple Id
  4. But when user login again after he/she chose “stop using apple Id on this app” on Settings, what information can I get?
    1. At first sign in after “stop using apple Id on this app”, I can get email value too.
    2. But at this time, user can choose “Hide My Email”
      1. If the user had chosen “Hide My Email” before, and chose “Hide My Email”, the address of relay email is same.
      2. But if user chose different option between “Hide My Email” and “Show My Email”, the value of email changes.
  5. Can I know if the user chose “Hide My Email”?
    1. Yes. If the user chose “Hide My Email”, email value has format <unique-alphanumeric-string>@privaterelay.appleid.com.
  6. Can I test on simulator?
    1. Yes. You need to login in Settings.

 

reference: https://forums.developer.apple.com/thread/119826

Problems of concurrency programming

  1. https://subscription.packtpub.com/book/application_development/9781785886126/1/ch01lvl1sec09/possible-problems-in-concurrent-applications
  2. 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.
  3. Problems
    1. 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
      1. Solutions: identify the critical section and make it accessible by only one thread at a time.
        1. Design: double check, especially after the long process and right before writing process
          1.  including avoiding shared global states, favor immutable over mutable values, using pure functions to minimize side-effects and adopting strategies like shared-nothing policy and Copy On Write (COW)

        2. locks in critical section
          1. methods
            1. NSLocks
            2. mutex
            3. semaphore
          2. 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.
          3. -> use serial dispatch queues instead
        3. submitting blocks on serial dispatch queue
        4. using .barriers flag on concurrent queue
    2. Priority Inversion:
    3. Deadlocks:
      1. submitting blocks on serial dispatch queue

Reference: https://medium.com/swiftcairo/avoiding-race-conditions-in-swift-9ccef0ec0b26