[docs] Extensions.md: Encoding & Errors + Core sections (Extensions.md complete)

This commit is contained in:
Daniel Arantes Loverde
2026-08-29 19:29:42 -03:00
parent 4f6a83556d
commit ec3442ed1c

View File

@@ -1674,7 +1674,71 @@ Full `dictionaryRepresentation()` — handy for debugging.
## Encoding & Errors
<!-- batch 7 -->
<details>
<summary><b>Encodable</b> — dictionary / JSON conversion</summary>
### `var dictionary: [String: Any]`
JSON-encode `self`, then reparse to a dictionary (`[:]` on failure).
```swift
struct Point: Encodable { let x = 1; let y = 2 }
Point().dictionary // ["x": 1, "y": 2]
```
### `var json: String` / `var data: Data`
Dictionary → JSON string / `Data`.
### `subscript(key: String) -> Any?`
Read one value from the encoded form.
```swift
Point()["x"] // 1
```
</details>
<details>
<summary><b>JSONDecoder</b> — decoding helpers</summary>
All return `T: Decodable & Sendable` and throw a **readable** `NSError` naming the
missing key / mismatched type / missing value on failure.
### `static func decode<T>(data: Data) throws -> T`
```swift
let user: User = try JSONDecoder.decode(data: responseData)
```
### `static func decode<T>(_ json: String, using encoding: String.Encoding = .utf8) throws -> T`
```swift
let user: User = try JSONDecoder.decode(#"{"id":1,"name":"Ana"}"#)
```
### `static func decode<T>(fromURL url: URL) throws -> T`
Read a file/URL then decode.
### `static func decode<T>(dictionary: Any) throws -> T`
Re-encode a dictionary/array to JSON then decode (uses `.convertFromSnakeCase`).
```swift
let user: User = try JSONDecoder.decode(dictionary: ["user_id": 1, "full_name": "Ana"])
```
</details>
<details>
<summary><b>NSError</b></summary>
### `static func createErrorWith(code: Int, description: String, reasonForError: String) -> NSError`
Build an `NSError` in the `LoverdeCoErrorDomain` with a localized description and
failure reason. Used throughout `API` for HTTP errors.
```swift
throw NSError.createErrorWith(code: 404, description: "Not found", reasonForError: body)
```
</details>
## Crypto
@@ -1781,4 +1845,174 @@ let dec = LCECryptoKitManager.otpDecode(enc ?? "") // "secret-value"
## Core — the `LCEssentials` namespace
<!-- batch 7 -->
<details>
<summary><b>Logging</b> — <code>printLog</code> / <code>printInfo</code> / <code>printWarn</code> / <code>printError</code></summary>
Four global functions used across the package. Each takes `title:` + `msg: Any`
and an optional `prettyPrint: Bool` (wraps the message in a START/END banner and,
for info/warn/error, prints the call-site file/function/line).
```swift
printLog(title: "STATE", msg: viewModel.state)
printError(title: "Decode", msg: error.localizedDescription, prettyPrint: true)
```
### Operator `a ^^ b`
Float exponentiation.
```swift
2.0 ^^ 10.0 // 1024.0
```
</details>
<details>
<summary><b>LCEssentials</b> — app / device / environment info (static, <code>@MainActor</code>)</summary>
### App info
| Property | Value |
|---|---|
| `appDisplayName` | `CFBundleDisplayName` |
| `appBundleID` | `Bundle.main.bundleIdentifier` |
| `appBuild` | build number string |
| `appVersion` | short version string |
| `applicationIconBadgeNumber` | get/set the icon badge (iOS/tvOS) |
```swift
LCEssentials.appVersion // "2.0.0"
LCEssentials.applicationIconBadgeNumber = 0
```
### Device / screen
| Property | Value |
|---|---|
| `currentDevice` | `UIDevice.current` / `WKInterfaceDevice.current()` |
| `screenWidth` / `screenHeight` | main screen bounds |
| `deviceOrientation` | `UIDeviceOrientation` (iOS) |
| `batteryLevel` | `Float` (iOS) |
| `systemVersion` | OS version string |
| `isPad` / `isPhone` | idiom checks (iOS) |
| `isMultitaskingSupported` | iOS |
```swift
if LCEssentials.isPad { }
LCEssentials.screenWidth
```
### Environment
| Property | Value |
|---|---|
| `isInDebuggingMode` | built in Debug |
| `isInTestFlight` | running a TestFlight build |
| `isRunningOnSimulator` | simulator target |
| `isRegisteredForRemoteNotifications` | push registration state |
| `isStatusBarHidden` | status-bar visibility (iOS) |
| `keyWindow` | current key `UIWindow` (iOS/tvOS) |
| `sharedApplication` | `UIApplication.shared` |
```swift
guard !LCEssentials.isRunningOnSimulator else { return }
```
### `static func sourceFileName(filePath: String) -> String`
Last path component of a `#file` string.
### `static func getTopViewController(base: UIViewController? = nil, aboveBars: Bool = true) -> UIViewController?`
Walk the presentation/navigation/tab hierarchy to the front-most controller.
`aboveBars: false` descends into the visible child of nav/tab containers.
```swift
let top = LCEssentials.getTopViewController()
top?.present(alert, animated: true)
```
</details>
<details>
<summary><b>LCEssentials</b> — threading, timing, sharing (static methods)</summary>
### `static func backgroundThread(delay: Double = 0, background: (@Sendable () -> Void)? = nil, completion: (@Sendable () -> Void)? = nil)`
Run `background` off the main queue, then `completion` on the main queue after `delay`.
```swift
LCEssentials.backgroundThread(delay: 0.3, background: {
let result = heavyWork()
}, completion: {
updateUI()
})
```
### `static func dispatchAsync(completion: @escaping () -> Void)`
`DispatchQueue.main.async` shorthand.
### `@discardableResult static func delay(milliseconds: Double, queue: DispatchQueue = .main, completion:) -> DispatchWorkItem`
Delayed call; keep the returned item to `.cancel()` it.
```swift
let task = LCEssentials.delay(milliseconds: 500) { fire() }
task.cancel() // if no longer needed
```
### `static func debounce(millisecondsDelay: Int, queue: DispatchQueue = .main, action:) -> () -> Void`
Returns a debounced wrapper — call it repeatedly, `action` runs at most once per idle window.
```swift
let search = LCEssentials.debounce(millisecondsDelay: 300) { runSearch() }
textField.onChange = search
```
### `static func didTakeScreenShot(_ action: @escaping (Notification) -> Void)` — *iOS/tvOS*
Observe `userDidTakeScreenshotNotification`.
### `static func shareApp(message: String = "", url: String = "")` — *UIKit*
Present a `UIActivityViewController` from the top view controller.
### `static func call(_ number: String)` / `static func openSafari(_ urlStr: String)` — *UIKit*
Open `tel://` / open a URL.
```swift
LCEssentials.call("+5511999999999")
LCEssentials.openSafari("https://loverde.com.br")
```
</details>
<details>
<summary><b>LCEssentials</b> — cached file download (iOS)</summary>
A shared 50 MB memory / 200 MB disk `URLCache` backs these.
### `static func downloadFileWithCache(from url: URL, completion: @escaping (Result<URL, Error>) -> Void)`
Return a local temp-file URL for a remote file, hitting the cache first.
```swift
LCEssentials.downloadFileWithCache(from: pdfURL) { result in
if case .success(let localURL) = result { showPDF(localURL) }
}
```
### `static func cachedFileURL(for url: URL) -> URL?`
Temp-file URL if the response is already cached, else `nil`.
### `static func cleanExpiredCache(expiration: TimeInterval = 7 days)`
Drop cached responses and temp files older than `expiration`.
</details>
<details>
<summary><b>LCESingletonDelegate</b></summary>
### `@objc protocol LCESingletonDelegate: AnyObject`
Optional callback `singleton(object: Any?, withData: Any)` — the delegate contract
for the package's singleton-style helpers.
```swift
final class Foo: NSObject, LCESingletonDelegate {
func singleton(object: Any?, withData: Any) { }
}
```
</details>