[docs] Extensions.md: Encoding & Errors + Core sections (Extensions.md complete)
This commit is contained in:
@@ -1674,7 +1674,71 @@ Full `dictionaryRepresentation()` — handy for debugging.
|
|||||||
|
|
||||||
## Encoding & Errors
|
## 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
|
## Crypto
|
||||||
|
|
||||||
@@ -1781,4 +1845,174 @@ let dec = LCECryptoKitManager.otpDecode(enc ?? "") // "secret-value"
|
|||||||
|
|
||||||
## Core — the `LCEssentials` namespace
|
## 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>
|
||||||
|
|||||||
Reference in New Issue
Block a user