-
-
Notifications
You must be signed in to change notification settings - Fork 19
Tips & Tricks
xcodebuild
CLI tool is slower than Xcode. This section provides a workaround to improve the build time.
The issue is caused by the fact that xcodebuild
tries to connect to the Apple
servers before building the project, which can take 20 seconds or more.
Usually, those requests are not necessary, but they slow down each build.
The workaround blocks developerservices2.apple.com
domain when the xcodebuild
tool is running by
modifying /etc/hosts
. Below you can find three ways to enable the workaround.
Warning
Keep in mind that disabling access to developerservices2.apple.com
for
xcodebuild
may cause some issues with the build process. It will disable
things like registering devices, capabilities, and other network-related
features. Therefore, it's best to use it when you are working just on the
code and don't need updating project settings.
1. Manual (script)
Enable workaround:
sudo bash -c "echo '127.0.0.1 developerservices2.apple.com' >>/etc/hosts"
Disable workaround:
sudo sed -i '' '/developerservices2\.apple\.com/d' /etc/hosts
2. Manual (network sniffer)
If you use some tool to sniff network traffic like Proxyman or Charles Proxy,
you can block requests to https://developerservices2.apple.com/*
and
automatically return some error like 999 status code. It will prevent
xcodebuild
from further calls.
3. Automatic (xcodebuild.nvim
integration)
In this approach the Apple server will be blocked only when the xcodebuild
command (triggered by the plugin) is running. However, it requires a passwordless
sudo
permission for the script.
Caution
Giving passwordless sudo access to that file, potentially opens a gate for malicious software
that could modify the file and run some evil code using root
account. The best way to protect
that file is to create a local copy, change the owner to root
, and give write permission only
to root
. The same must be applied to the parent directory. The script below automatically secures
the file.
👉 Enable integration that automatically blocks Apple servers
Update your config with:
integrations = {
xcodebuild_offline = {
enabled = true,
},
}
👉 Run the following command to install & protect the script
DEST="$HOME/Library/xcodebuild.nvim" && \
SOURCE="$HOME/.local/share/nvim/lazy/xcodebuild.nvim/tools/xcodebuild_offline" && \
ME="$(whoami)" && \
sudo install -d -m 755 -o root "$DEST" && \
sudo install -m 755 -o root "$SOURCE" "$DEST" && \
sudo bash -c "echo \"$ME ALL = (ALL) NOPASSWD: $DEST/xcodebuild_offline\" >> /etc/sudoers"
More details about this issue can be found here: #201
If you switch between Neovim and Xcode you most likely want a feature that automatically refreshes changed files.
The only reliable solution I found is:
vim.opt.autoread = true
-- refresh files if changed outside
vim.fn.timer_start(2000, function()
vim.cmd("silent! checktime")
end, { ["repeat"] = -1 })
Often, you want to have templates for specific files in your project or at least you want to have a header (like when using Xcode).
I created a small function that fills in a new file with a predefined template. Based on the file name suffix it can use the relevant template.
This function is also able to replace some placeholders like {date}
, {filename}
, and {name}
. If you place {cursor}
in your template, the cursor will be automatically moved there.
vim.api.nvim_create_autocmd({ "BufNewFile", "BufReadPost" }, {
group = "bufcheck",
pattern = "*.swift",
callback = function(ev)
local lines = #vim.api.nvim_buf_get_lines(ev.buf, 0, -1, false)
if lines > 1 then
return
end
local filename = string.match(ev.file, "([^/]*)%.swift")
local name = filename
-- TODO: make sure this path leads to your folder with templates!!
local basepath = os.getenv("HOME") .. "/.config/YOUR_CONFIG_PATH/templates/"
local templates = { "View", "ViewModel", "Builder", "Router", "Tests", "Spec" }
local template
local cursor
for _, templateSuffix in ipairs(templates) do
if vim.endswith(filename, templateSuffix) then
template = vim.fn.readfile(basepath .. string.lower(templateSuffix) .. ".txt")
name = string.gsub(name, templateSuffix, "")
break
end
end
template = template or vim.fn.readfile(basepath .. "empty.txt")
for i = 1, #template do
template[i] = string.gsub(template[i], "{date}", os.date("%d/%m/%Y"))
template[i] = string.gsub(template[i], "{filename}", filename)
template[i] = string.gsub(template[i], "{name}", name)
if cursor == nil and string.find(template[i], "{cursor}") then
cursor = { i, tonumber(string.find(template[i], "{cursor}")) + 1 }
end
template[i] = string.gsub(template[i], "{cursor}", " ")
end
vim.api.nvim_buf_set_lines(ev.buf, 0, -1, false, template)
if cursor then
vim.api.nvim_win_set_cursor(0, cursor)
end
vim.cmd("w")
end,
})
Sample template templates/viewmodel.txt
//
// {filename}.swift
//
//
// Created by YOUR_NAME on {date}.
// Copyright © 2024 YOUR_COMPANY. All rights reserved.
//
import Foundation
protocol {filename}Protocol: ObservableObject {
var someProperty: String { get }
}
final class {filename}: {filename}Protocol {
@Published var someProperty: String = ""
init() {
{@cursor@}
}
}
If you want to try out new features from sourcekit-lsp, you need to switch to Swift Development snapshot. Below you can find steps required to do that:
- Download the latest snapshot for Xcode from here
- Install it.
- Switch to it from Xcode (menu bar -> Xcode -> Toolchains)
- Run (make sure that the path matches your version)
sudo cp `xcode-select -p`/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/*/lib/darwin/libclang_rt.*.a /Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2024-03-07-a.xctoolchain/usr/lib/clang/17/lib/darwin/
- Switch your LSP config to point to the new
sourcekit-lsp
:lspconfig["sourcekit"].setup({ capabilities = capabilities, on_attach = on_attach, cmd = { "/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2024-03-07-a.xctoolchain/usr/bin/sourcekit-lsp", }, -- ... },
- Add additional flags to build and test from Neovim using the latest toolchain. Update your xcodebuild.nvim setup options:
commands = { extra_build_args = "-parallelizeTargets -toolchain swift-latest", extra_test_args = "-parallelizeTargets -toolchain swift-latest", },
- Clean & build the project from Xcode.
- Open project in Neovim as usual. New features like smart rename should be available.
In Neovim you can't use SwiftUI previews.
However, you can integrate tools that add a hot reload feature for iOS apps. Here are two essential tools that you need:
There is no easy way to debug view hierarchy outside of Xcode.
However, there is a paid alternative. If you are interested, check out this issue: #213.