From ec3442ed1c4d9c84dd6f33bbd6aa912a6a7c3e80 Mon Sep 17 00:00:00 2001 From: Daniel Arantes Loverde Date: Sat, 29 Aug 2026 19:29:42 -0300 Subject: [PATCH] [docs] Extensions.md: Encoding & Errors + Core sections (Extensions.md complete) --- Documentation/Extensions.md | 238 +++++++++++++++++++++++++++++++++++- 1 file changed, 236 insertions(+), 2 deletions(-) diff --git a/Documentation/Extensions.md b/Documentation/Extensions.md index a5c4da5..4a02881 100644 --- a/Documentation/Extensions.md +++ b/Documentation/Extensions.md @@ -1674,7 +1674,71 @@ Full `dictionaryRepresentation()` — handy for debugging. ## Encoding & Errors - +
+Encodable — dictionary / JSON conversion + +### `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 +``` + +
+ +
+JSONDecoder — decoding helpers + +All return `T: Decodable & Sendable` and throw a **readable** `NSError` naming the +missing key / mismatched type / missing value on failure. + +### `static func decode(data: Data) throws -> T` + +```swift +let user: User = try JSONDecoder.decode(data: responseData) +``` + +### `static func decode(_ json: String, using encoding: String.Encoding = .utf8) throws -> T` + +```swift +let user: User = try JSONDecoder.decode(#"{"id":1,"name":"Ana"}"#) +``` + +### `static func decode(fromURL url: URL) throws -> T` +Read a file/URL then decode. + +### `static func decode(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"]) +``` + +
+ +
+NSError + +### `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) +``` + +
## Crypto @@ -1781,4 +1845,174 @@ let dec = LCECryptoKitManager.otpDecode(enc ?? "") // "secret-value" ## Core — the `LCEssentials` namespace - +
+LoggingprintLog / printInfo / printWarn / printError + +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 +``` + +
+ +
+LCEssentials — app / device / environment info (static, @MainActor) + +### 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) +``` + +
+ +
+LCEssentials — threading, timing, sharing (static methods) + +### `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") +``` + +
+ +
+LCEssentials — cached file download (iOS) + +A shared 50 MB memory / 200 MB disk `URLCache` backs these. + +### `static func downloadFileWithCache(from url: URL, completion: @escaping (Result) -> 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`. + +
+ +
+LCESingletonDelegate + +### `@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) { … } +} +``` + +