[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-6967":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":15,"stars7d":17,"stars30d":18,"stars90d":16,"forks30d":16,"starsTrendScore":19,"compositeScore":20,"rankGlobal":10,"rankLanguage":10,"license":21,"archived":22,"fork":22,"defaultBranch":23,"hasWiki":24,"hasPages":22,"topics":25,"createdAt":10,"pushedAt":10,"updatedAt":30,"readmeContent":31,"aiSummary":32,"trendingCount":16,"starSnapshotCount":16,"syncStatus":33,"lastSyncTime":34,"discoverSource":35},6967,"Inject","krzysztofzablocki\u002FInject","krzysztofzablocki","Hot Reloading for Swift applications! ","",null,"Swift",3447,147,18,3,0,6,21,10,28.51,"MIT License",false,"main",true,[26,27,28,29],"hot-reload","ios","swift","swiftui","2026-06-12 02:01:32","# Inject\nHot reloading workflow helper that enables you to save hours of time each week, regardless if you are using `UIKit`, `AppKit` or `SwiftUI`.\n\n[**If you'd like to support my work and improve your engineering workflows, check out my SwiftyStack course**](https:\u002F\u002Fwww.swiftystack.com\u002F)\n\n**TLDR: A single line of code** change allows you to live code `UIKit` screen:\n\n\nhttps:\u002F\u002Fuser-images.githubusercontent.com\u002F26660989\u002F161756368-b150bc25-b66f-4822-86ee-2e4aed713932.mp4\n\n\n\n[Read detailed article about this](https:\u002F\u002Fmerowing.info\u002F2022\u002F04\u002Fhot-reloading-in-swift\u002F)\n\nThe heavy lifting is done by the amazing [InjectionIII](https:\u002F\u002Fgithub.com\u002Fjohnno1962\u002FInjectionIII). This library is just a thin wrapper to provide the best developer experience possible while requiring minimum effort. \n\nI've been using it for years.\n\n## What is hot reloading?\nHot reloading is a technique allowing you to get rid of compiling your whole application and avoiding deploy\u002Frestart cycles as much as possible, all while allowing you to edit your running application code and see changes reflected as close as possible to real-time.\n\nThis makes you significantly more productive by reducing the time you spend waiting for apps to rebuild, restart, re-navigate to the previous location where you were in the app itself, re-produce the data you need.\n\nThis can save you literal hours off development time, **each day**! \n\n## Does it add manual overhead to my workflows?\nOnce you configured your project initially, it's practically free.\n\nYou don’t need to add conditional compilation or remove `Inject` code from your applications for production, it's already designed to behave as no-op inlined code that will get stripped by LLVM in non-debug builds. \n\nWhich means that you can enable it once per view and keep using it for years to come.\n\n# Integration\n### Initial project setup\n\nTo integrate `Inject` just add it as SPM dependency:\n\n### via Xcode\n\nOpen your project, click on File → Swift Packages → Add Package Dependency…, enter the repository url (`https:\u002F\u002Fgithub.com\u002Fkrzysztofzablocki\u002FInject.git`) and add the package product to your app target.\n\n### via SPM package.swift\n\n```swift\ndependencies: [\n    .package(\n      url: \"https:\u002F\u002Fgithub.com\u002Fkrzysztofzablocki\u002FInject.git\",\n      from: \"1.2.4\"\n    )\n]\n```\n\n### via Cocoapods Podfile\n\n```ruby\npod 'InjectHotReload'\n```\n\n### Individual Developer setup (once per machine)\nIf anyone in your project wants to use injection, they only need to:\n\n- You must add \"-Xlinker -interposable\" (without the double quotes and on separate lines) to the \"Other Linker Flags\" of all targets in your project for the **Debug** configuration (qualified by the simulator SDK to avoid complications with bitcode), refer to [InjectionForXcode documentation](https:\u002F\u002Fgithub.com\u002Fjohnno1962\u002FInjectionIII#limitationsfaq) if you run into any issues\n- Also in newer Xcode need to go to \"Editor\u002FAdd Build Setting\u002FAdd User-Defined Setting\" and add a value for EMIT_FRONTEND_COMMAND_LINES (set to \"YES\") to your project's Debug build settings\n-  Download newest version of Xcode Injection from it's [GitHub Page](https:\u002F\u002Fgithub.com\u002Fjohnno1962\u002FInjectionIII\u002Freleases)\n  - Unpack it and place under `\u002FApplications`\n- Make sure that the Xcode version you are using to compile our projects is under the default location: `\u002FApplications\u002FXcode.app`\n- Run the injection application\n- Select open project \u002F open recent from it's menu and pick the right workspace file you are using\n\n After choosing the project in Injection app, launch the app\n- If everything is configured correctly you should see similar log in the console:\n\n```bash\n💉 InjectionIII connected \u002FUsers\u002Fmerowing\u002Fwork\u002FSourceryPro\u002FApp.xcworkspace\n💉 Watching files under \u002FUsers\u002Fmerowing\u002Fwork\u002FSourceryPro\n```\n\n## Workflow integration\nYou can either add `import Inject` in individual files in your project or use \n`@_exported import Inject` in your project target to have it automatically available in all its files.\n\n#### **SwiftUI**\nJust 2 steps to enable injection in your `SwiftUI` Views\n\n- call `.enableInjection()` at the end of your body definition\n- add `@ObserveInjection var inject` to your view struct\n\n> *Remember you **don't need** to remove this code when you are done, it's NO-OP in production builds.*\n\nIf you want to see your changes in action, you can enable an optional `Animation` variable on `InjectConfiguration.animation` that will be used when ever new source code is injected into your application.\n\n```swift\nInjectConfiguration.animation = .interactiveSpring()\n```\n\nUsing `Inject` is demoed in this [example app](https:\u002F\u002Fgithub.com\u002FMarcoEidinger\u002FInjectSwiftUIExample) \n\n####  **UIKit \u002F AppKit**\nFor standard imperative UI frameworks we need a way to clean-up state between code injection phases. \n\nI create the concept of **Hosts** that work really well in that context, there are 2:\n\n- `ViewControllerHost`\n- `ViewHost`\n\nHow do we integrate this? We wrap the class we want to iterate on at the parent level, so we don’t modify the class we want to be injecting but we modify the parent callsite.\n\nEg. If you have a `SplitViewController` that creates `PaneA` and `PaneB `, and you want to iterate on layout\u002Flogic code in `PaneA`, you modify the callsite in `SplitViewController`:\n\n```swift\npaneA = Inject.ViewHost(\n  PaneAView(whatever: arguments, you: want)\n)\n```\n\nThat is all the changes you need to do, your app now allows you to change anything in `PaneAView` except for its initialiser API and the changes will be almost immediately reflected in your App.\n\nMake sure to call initializer inside `Inject.ViewControllerHost(...)` or `Inject.ViewHost(...)`. Inject relies on `@autoclosure` to reload views when hot-reload happens. Example:\n```swift\n\u002F\u002F WRONG\nlet viewController = YourViewController()\nrootViewController.pushViewController(Inject.ViewControllerHost(viewController), animated: true)\n\n\u002F\u002F CORRECT\nlet viewController = Inject.ViewControllerHost(YourViewController())\nrootViewController.pushViewController(viewController, animated: true)\n```\n> *Remember you **don't need** to remove this code when you are done, it's NO-OP in production builds.*\n\n\n####  **Injection Hook for UIKit**\ndepending on the architecture used in your UIKit App, you might want to attach a hook to be executed each time a view controller is reloaded.\n\nEg. you might want to bind the `UIViewController` to the presenter each-time there's a reload, to achieve this you can use `onInjectionHook`\n   Example:\n\n```swift\nmyView.onInjectionHook = { hostedViewController in\n\u002F\u002Fany thing here will be executed each time the controller is reloaded\n\u002F\u002F for example, you might want to re-assign the controller to your presenter\npresenter.ui = hostedViewController\n}\n```\n\n## (Optional) Automatic Injection Script\n\n> **WARNING:** This script automatically modifies your Swift source code. It's provided as a convenience but use it with caution!  Review the changes it makes carefully. It might not be suitable for all projects or coding styles. Consider using Xcode code snippets for more manual control.\n\nTo automatically add `import Inject`, `@ObserveInjection var inject`, and `.enableInjection()` to your SwiftUI views, you can add the following script as a \"Run Script\" build phase in your Xcode project:\n\n```sh\n#!\u002Fbin\u002Fbash\n\n# Function to modify a single Swift file\nmodify_swift_file() {\n    local filepath=\"$1\"\n    local filename=$(basename \"$filepath\")\n    local tempfile=\"$filepath.tmp\"\n\n    # Check if the file should be processed\n    if [[ $(grep -c \": View {\" \"$filepath\") -eq 0 ]]; then\n        echo \"Skipping: $filename (No ': View {' found)\"\n        return\n    fi\n\n    # Create a temporary file for modifications\n    cp \"$filepath\" \"$tempfile\"\n\n    # 1. Add import Inject if needed\n    if ! grep -q \"import Inject\" \"$tempfile\"; then\n        sed -i '' -e '\u002F^import SwiftUI\u002Fa\\\nimport Inject' \"$tempfile\"\n    fi\n\n    # 2. Add @ObserveInjection var inject if needed\n    if ! grep -q \"@ObserveInjection var inject\" \"$tempfile\"; then\n        sed -i '' -e '\u002Fstruct.*: View {\u002Fa\\\n    @ObserveInjection var inject' \"$tempfile\"\n    fi\n\n    # 3. Add .enableInjection() just before the closing brace of the body\n    # Find the start of var body: some View {\n    local body_start_line=$(grep -n \"var body: some View {\" \"$tempfile\" | cut -d ':' -f 1)\n\n    if [[ -n \"$body_start_line\" ]]; then\n        # Get the line number of the closing brace of the body\n        local body_end_line=$(awk -v start=\"$body_start_line\" '\n            NR == start { count = 1 }\n            NR > start {\n                if ($0 ~ \u002F{\u002F) count++\n                if ($0 ~ \u002F}\u002F) {\n                    count--\n                    if (count == 0) {\n                        print NR\n                        exit\n                    }\n                }\n            }\n        ' \"$tempfile\")\n\n        if [[ -n \"$body_end_line\" ]]; then\n            # Check if .enableInjection() is already present\n            if ! grep -q \".enableInjection()\" \"$tempfile\"; then\n                # Insert .enableInjection() before the closing brace of the body\n                sed -i '' -e \"${body_end_line}i\\\\\n        .enableInjection()\" \"$tempfile\"\n            fi\n        fi\n    fi\n\n    # Check if modifications were made and overwrite the original file\n    if ! cmp -s \"$filepath\" \"$tempfile\"; then\n        mv \"$tempfile\" \"$filepath\"\n        echo \"Modified: $filename\"\n    else\n        echo \"No changes for: $filename\"\n    fi\n\n    rm -f \"$tempfile\"\n}\n\n# Main script\nfind \"$SRCROOT\" -name \"*.swift\" -print0 | while IFS= read -r -d $'\\0' filepath; do\n    modify_swift_file \"$filepath\"\ndone\n\necho \"Inject modification script completed.\"\n```\n\n#### iOS 12\nYou need to add -weak_framework SwiftUI to Other Linker Flags for iOS 12 to work.\n\n#### The Composable Architecture\n\nSince the introduction of ReducerProtocol you can use Inject with TCA without support code.\n","Inject 是一个用于 Swift 应用程序的热重载工具，能够显著提高开发效率。其核心功能在于允许开发者在不重新编译整个应用的情况下实时查看代码更改的效果，支持 UIKit、AppKit 以及 SwiftUI 框架。通过简单的集成步骤，只需一行代码即可激活热重载功能，并且设计为在非调试构建中被 LLVM 自动移除，从而不会对生产环境造成影响。此工具特别适合需要频繁迭代界面和逻辑的 iOS 或 macOS 开发场景，能够极大减少等待应用重建的时间，使开发者每天节省数小时的工作时间。",2,"2026-06-11 03:09:53","top_language"]