【Swift】少数の丸め方あれこれ - rounded()

こんなにあったのですか。


5.2
.rounded() 5.0
.rounded(.down) 5.0
.rounded(.up) 6.0
.rounded(.towardZero) 5.0
.rounded(.awayFromZero) 6.0
.rounded(.toNearestOrEven) 5.0
.rounded(.toNearestOrAwayFromZero) 5.0

5.5
.rounded() 6.0
.rounded(.down) 5.0
.rounded(.up) 6.0
.rounded(.towardZero) 5.0
.rounded(.awayFromZero) 6.0
.rounded(.toNearestOrEven) 6.0
.rounded(.toNearestOrAwayFromZero) 6.0

-5.2
.rounded() -5.0
.rounded(.down) -6.0
.rounded(.up) -5.0
.rounded(.towardZero) -5.0
.rounded(.awayFromZero) -6.0
.rounded(.toNearestOrEven) -5.0
.rounded(.toNearestOrAwayFromZero) -5.0

-5.5
.rounded() -6.0
.rounded(.down) -6.0
.rounded(.up) -5.0
.rounded(.towardZero) -5.0
.rounded(.awayFromZero) -6.0
.rounded(.toNearestOrEven) -6.0
.rounded(.toNearestOrAwayFromZero) -6.0

0.51
.rounded() 1.0
.rounded(.down) 0.0
.rounded(.up) 1.0
.rounded(.towardZero) 0.0
.rounded(.awayFromZero) 1.0
.rounded(.toNearestOrEven) 1.0
.rounded(.toNearestOrAwayFromZero) 1.0

0.0
.rounded() 0.0
.rounded(.down) 0.0
.rounded(.up) 0.0
.rounded(.towardZero) 0.0
.rounded(.awayFromZero) 0.0
.rounded(.toNearestOrEven) 0.0
.rounded(.toNearestOrAwayFromZero) 0.0

0.03
.rounded() 0.0
.rounded(.down) 0.0
.rounded(.up) 1.0
.rounded(.towardZero) 0.0
.rounded(.awayFromZero) 1.0
.rounded(.toNearestOrEven) 0.0
.rounded(.toNearestOrAwayFromZero) 0.0

1.001
.rounded() 1.0
.rounded(.down) 1.0
.rounded(.up) 2.0
.rounded(.towardZero) 1.0
.rounded(.awayFromZero) 2.0
.rounded(.toNearestOrEven) 1.0
.rounded(.toNearestOrAwayFromZero) 1.0

👉 rounded(_:) | Apple Developer Documentation hatena-bookmark
👉 round() | Apple Developer Documentation hatena-bookmark
👉 FloatingPointRoundingRule | Apple Developer Documentation hatena-bookmark

 

🧑‍💻 チャートにしてみる

視覚化してみると全然ちげえ !



 

🧑‍💻 まとめ

僕たちが日頃使っている四捨五入は、


.rounded()

で、


.rounded(.toNearestOrAwayFromZero)

のことと同じで、

「schoolbook rounding (教科書丸め)」

と呼ばれているようです。

「bankers rounding (銀行丸め)」

とか、要領よく出来てるんですね !

👉 端数処理 - Wikipedia hatena-bookmark

ちなみに「四捨五入」って多すぎ。

👉 Rounding a double value to x number of decimal places in swift - Stack Overflow hatena-bookmark



【SwiftUI】#Preview with @Binding arguments

#Preview@Binding の引数を持つ View をどう書くか。

サンプルとして以前のコードを使います。


.constant() を使うか、@State + return を使うか。


#Preview(".constant(\"\")") {
  TestSearchTextField(text: .constant(""))
    .frame(width: 300)
}

#Preview(".constant(\"dog\")") {
  TestSearchTextField(text: .constant("dog"))
    .frame(width: 300)
}

#Preview("return") {
  @State var text = "dog"
  return TestSearchTextField(text: $text)
    .frame(width: 300)
}

View パーツの確認をすばやく #Preview で確認できるようになりました !


【Swift】ログイン時に起動する - SMAppService


import Foundation
import ServiceManagement
import os.log

@available(macOS 13.0, *)
public enum LaunchOnLogin {
  public static var isEnabled: Bool {
    get { SMAppService.mainApp.status == .enabled }
    set {
      do {
        if newValue {
          if SMAppService.mainApp.status == .enabled {
            try? SMAppService.mainApp.unregister()
          }
          try SMAppService.mainApp.register()
        } else {
          try SMAppService.mainApp.unregister()
        }
      } catch {
        os_log("Failed to \(newValue ? "enable" : "disable") launch at login: \(error.localizedDescription)")
      }
    }
  }
}

👉 Rectangle/Rectangle/LaunchOnLogin.swift at 277cadc905d9ff92c7948a5c97794141f8d1277c · rxhanson/Rectangle hatena-bookmark


import AppKit
import ServiceManagement

@available(macOS 13.0, *)
class LoginItemManager {
  func loginItemIsEnabled() -> Bool {
    return SMAppService.mainApp.status == .enabled
  }

  func disableLoginItem() {
    try? SMAppService.mainApp.unregister()
  }

  func enableLoginItem() {
    try? SMAppService.mainApp.register()
  }
}

👉 phpmon/phpmon/Common/Helpers/LoginItemManager.swift at 4a3dee3c5023ef252e5dd48de4d2937087eb941b · nicoverbruggen/phpmon hatena-bookmark


import ServiceManagement

public extension SMAppService {
  var isEnabled: Bool {
    status == .enabled
  }

  func toggle() throws {
    isEnabled ? try unregister() : try register()
  }
}

👉 LunarBar/LunarBarMac/Modules/Sources/AppKitExtensions/SMAppService+Extension.swift at e7ae92a8fca7895d739686839afa450fd60663de · LunarBar-app/LunarBar hatena-bookmark

 

■ まとめ

以上を参考に、こう書きました。


@AppStorage("launchAtLogin") private var isOn = false

Toggle("Launch at login", isOn: $isOn)
  .onAppear {
    isOn = SMAppService.mainApp.status == .enabled
  }
  .onChange(of: isOn) {
    let app = SMAppService.mainApp
    try? isOn ? app.register() : app.unregister()
  }

その後、結局、

@AppStorage も @State も持たないようにしました。



登録状態は、


[Settings] - [General] - [Login Items]

でOS側設定画面からも管理できます。

しかし、双方向のバインディングはつらくないですか。

👉 SMAppService | Apple Developer Documentation hatena-bookmark