今日已更新 133 条资讯 | 累计 37382 条内容
关于我们

标签:#Swift

找到 51 篇相关文章

AI 资讯

Why I Built an SSH Config and Tunnel Manager for macOS

Every internal tool I need sits behind SSH. Grafana, Prometheus, the staging clusters, internal AI tooling—none of it answers on a public address, and the only door is a bastion I have a key for. That is the right setup for anything with real data behind it, and I wouldn't change it. What I did change is typing ssh -N -L 3000:localhost:3000 -J bastion prod-1 from memory four times a day across three different machines. So one weekend, I started writing SSH Config Manager . It is a native macOS app that edits ~/.ssh/config without wrecking formatting, saves tunnels as presets, and opens those tunnels in-process instead of shelling out to ssh . I wrote it for my own workflow first. Putting it on the App Store came later, once it was genuinely useful to me and I figured others were struggling with the exact same friction. The VPN Question The first thing people ask is: why not run a VPN and be done with it? Fair question, but the honest answer is that SSH is the tool I already understand inside and out. I have configured sshd enough times to know what PermitRootLogin no and PasswordAuthentication no actually change. When a connection stops working, I can usually name the exact line that broke it. A VPN introduces a whole second network layer underneath, complete with its own credentials, its own background daemon to keep patched, and its own unique failure modes to debug at 2:00 AM when production is down. SSH is already on every Linux server I touch and every developer machine I own — there is nothing new to roll out and nothing new to secure. The tradeoff is real, and I would rather acknowledge it up front. Operating without a VPN means no transparent network routing: every internal service I want to reach must be explicitly forwarded to a local port in advance, and a colleague without my config reaches none of them. Still, I would far rather maintain a clean list of port forwards than maintain another background daemon. Shell Aliases Do Not Survive Three Machines Th

2026-08-27 原文 →
AI 资讯

I set the font to the largest size and found the same bug eleven times

I was cleaning up the UI on a side-project iOS app and did one thing: set Dynamic Type to XXXL and screenshot every screen. Reading the code had turned up nothing. The screenshots showed problems immediately. Eleven of them, in the end. All the same cause. Here's the conclusion first. "A parent that pins things side by side" × "text that grows" is not a bug, it's a pattern. And in Japanese it breaks reliably worse than in English. English truncates. Japanese stacks vertically. Same layout, different failure depending on language. English wraps at word boundaries and, failing that, ends in … . You can't read it, but you can tell something was cut. Japanese doesn't do that. It can break between almost any two characters, so once a column is squeezed to one character wide, you get one character per line, stacked downward. Actual output: Rendered Intended Paire / d / Macs Paired Macs ( broken mid-word ) Claud / e / Code Claude Code One character per line "実行中のセッション" (Running sessions) Three step labels stacked vertically A three-step horizontal stepper De / mo , turning the capsule into a circle A "Demo" badge Paire / d / Macs is English breaking mid-word. Once the column has only a few characters left, even English gets there. Japanese gets there much earlier. The cause had the same shape every time Nearly all eleven were this: HStack { Image ( systemName : icon ) . frame ( width : 44 ) // fixed Text ( label ) Spacer () Text ( value ) // pinned right } The 44pt icon and the trailing value claim their width first, leaving the label column a few characters. The fix: rows that carry a value drop the value to the line below — but affordances like chevrons and toggles stay on the right. That row component was shared across the whole settings tree, so fixing one place fixed the entire settings screen. Which also means one decision inside a shared component was breaking eleven screens. ViewThatFits is not a general answer I used ViewThatFits to switch to a stacked layout. It

2026-08-16 原文 →
AI 资讯

Rendering a live 3D earthquake globe on iOS from the USGS feed

I wanted to see earthquakes the way they actually happen: as points lighting up on a spinning planet, in near real time. That became Earthquake: Live Seismic Monitor , an iOS app that renders a 3D globe of recent quakes straight from the USGS feed. No backend of my own - just the public data and the device. Here's how it comes together. The data source The USGS publishes earthquake data as GeoJSON feeds, updated continuously, at several time/magnitude cutoffs (past hour, past day, 2.5+, 4.5+, etc). Each feature has coordinates, magnitude, depth and time. That's everything you need to place a quake on a globe - no custom API required. The app polls the appropriate feed, diffs against what it already has, and updates the scene. Because USGS does the heavy lifting, the whole thing is effectively serverless from my side. Putting quakes on a globe The core mapping problem is turning (latitude, longitude) into a point on a sphere. Once you have that, each earthquake becomes a marker whose size and color encode magnitude and depth, so a glance tells you "big and shallow" vs "small and deep". Design decisions that mattered: Encode magnitude visually. Radius and color do more than any label. A magnitude 6 should look like a magnitude 6. Cluster sensibly. Active regions produce swarms; markers need to stay readable when dozens land in one area. Keep the globe interactive. Rotate, zoom, tap a quake for details. It should feel like an object, not a chart. Real-time without a server Every network-dependent app has to answer: what happens offline, and how fresh is "live"? My rules: Cache the last good feed so the globe still renders with no connection. Refresh on foreground and on an interval, and show the data's own timestamp so "live" is honest. Never block the UI on the network - render what you have, then update. Why no backend It's tempting to proxy the feed through your own server "for control". But USGS is reliable, public, and built for exactly this. Skipping a backend me

2026-08-10 原文 →
AI 资讯

Swift Protocols — Opaque Return Types and the Mystery of `some` 🔮

You've seen some View in every SwiftUI file you've ever opened. Now let's find out what it actually means, why it exists, and why returning a plain protocol doesn't work the same way. Fair warning: this topic is genuinely one of the more brain-bendy things in Swift. I'm going to tell you upfront that you don't need to fully understand the internals to keep going — but you do need to know it exists and roughly what it's doing, because you've already been using it every single time you've written a SwiftUI view. That some View in every SwiftUI file? That's an opaque return type. And now we're going to actually understand what that means. 🍥 Let's Start With Something That Works Two simple functions: func getRandomJutsu () -> Int { Int . random ( in : 1 ... 100 ) } func getRandomSuccess () -> Bool { Bool . random () } Both Int and Bool conform to a protocol called Equatable — which means they can be compared using == . So you can do this: print ( getRandomJutsu () == getRandomJutsu ()) That works fine, comparing two random integers. Now, since both return types conform to Equatable , you might think: what if we simplify both functions to return Equatable instead of their specific types? The Thing That Doesn't Work func getRandomJutsu () -> Equatable { // ❌ Int . random ( in : 1 ... 100 ) } func getRandomSuccess () -> Equatable { // ❌ Bool . random () } Swift refuses this with an error message so confusing it might as well be written in ancient runes: "protocol 'Equatable' can only be used as a generic constraint because it has Self or associated type requirements." Here's the actual problem in plain English: if both functions return Equatable , Swift loses track of what specific type is coming back. And if it doesn't know the specific type, it can't know whether two Equatable things can actually be compared to each other. Think about it: an Int and a Bool both conform to Equatable , but you can't compare them with == . That doesn't make sense. Swift isn't going to let y

2026-08-08 原文 →
AI 资讯

Understanding MVVM by Building a Simple Weather App with SwiftUI

MVVM with swiftUI When learning SwiftUI, one of the first architectural patterns you'll encounter is MVVM (Model-View-ViewModel). In this tutorial, we'll build a simple weather application that consumes the OpenWeather API while applying MVVM, dependency injection, and protocol-oriented programming. By the end, you'll understand not only how to structure the project, but also why each layer exists. This is the link for the OpenWeather API https://openweathermap.org/api . What you'll learn By the end of this tutorial you'll know how to: Structure a SwiftUI project using MVVM. Consume a REST API using async/await. Apply dependency injection using protocols. Display loading and error states. Keep Views focused only on UI. This is how the data flow looks. User taps "Search" │ ▼ ┌──────────────┐ │ ContentView │ └──────┬───────┘ │ await fetchWeather() │ ▼ ┌────────────────────┐ │ WeatherViewModel │ └─────────┬──────────┘ │ ▼ WeatherServiceProtocol │ ▼ ┌─────────────────┐ │ WeatherService │ └──────┬──────────┘ │ ▼ OpenWeather API Project Structure WeatherApp ├── Configuration │ └──AppConfig.swift ├── Models │ ├── Main.swift │ ├── Weather.swift │ └── WeatherResponse.swift ├── Services │ ├── WeatherService.swift │ └── WeatherServiceProtocol.swift ├── ViewModels │ └── WeatherViewModel.swift └── Views └── ContentView.swift Configuration contains application-wide constants such as the API key and base URLs. Models contains the data structures used to decode the API response. Services is responsible for networking and fetching data. ViewModels contains the presentation logic and exposes data to the UI. Views contains the SwiftUI interface. On the AppConfig file, we are going to keep static info, just like the base URL, API key, etc struct AppConfig { static let apiKey = "YOUR API KEY" static let baseGeoCodingAPIURL = "https://api.openweathermap.org/geo/1.0/direct?q=" static let baseURL = "https://api.openweathermap.org/data/2.5/weather?&units=metric&lat=" } Designing the UI Befo

2026-08-06 原文 →
AI 资讯

WWDC’26 Viewing Guide

I've been following WWDC since 2011* and over the years I've developed my own process for watching sessions. Over the past 15 years, I've gone through all the stages from denial (I missed all the videos, for example, in 2014, when I couldn't accept Swift's appearance), to bargaining ("I still CAN watch all of them!") and finally accepting and creating my own approach to watching WWDC. So here's my current approach: I try to watch Keynote and Platforms State of the Union at the time of their live broadcast or in the early days. When all the sessions become available, I sit down and go through all the titles and descriptions and choose what I will watch. All sessions fall into 4 categories: Essential is a must watch and should never be missed Nice To Watch is something interesting to me personally and may be applicable to what I work with Only If I Have Time is for optional sessions that interested me, but if I skip them, then nothing terrible will happen Everything else Thus, I clearly identify a fairly small set of sessions that I definitely need to watch, usually it's about 10 sessions and I don't feel any FOMO or pressure that there is so much new and how and when to watch it all. Most of the time, it takes me all summer to slowly watch everything from Essential, a few (or all, it depends) Nice To Watch, and sometimes a couple, and sometimes nothing at all from Only If I Have Time. An important rule for me is to watch Essential first. Then I can do whatever I want. Another personal kink of mine is to watch the sessions in the order of their numbering. For example, in my Essential category, the very first video is 227. Create UI prototypes using agents in Xcode , and then 258. What’s new in Xcode 27 and so on. So, here is my personal list of WWDC’26 sessions, divided into these categories: Essential Create UI prototypes using agents in Xcode What’s new in Xcode 27 Xcode, agents and you Get the most out of Device Hub What’s new in Swift What’s new in SwiftUI Moderni

2026-07-29 原文 →
AI 资讯

Privacy-First Health: Running Llama-3 Locally on iPhone with MLX-Swift

In the age of "Cloud Everything," our most sensitive data—our heartbeat, our sleep cycles, our stress levels—often ends up on a server somewhere in Northern Virginia. But what if we could keep that data where it belongs? On your device. Today, we're diving deep into Edge AI and On-device LLMs . We will build a privacy-centric health coach that uses MLX-Swift to run Llama-3 directly on your iPhone's Apple Silicon. We’ll be pulling real-time Heart Rate Variability (HRV) data from the HealthKit API and generating semantic health summaries without a single byte ever leaving your phone. 🚀 Why Edge AI? 🛡️ When dealing with Private AI and sensitive medical metrics, the "Cloud-First" approach is a liability. By leveraging MLX-Swift and the Unified Memory Architecture of the A17 Pro/A18 chips, we achieve: Zero Latency : No round-trip to a server. Total Privacy : Your data stays in the Secure Enclave. Offline Capability : Health insights in the middle of the woods? Yes. The Architecture 🏗️ The data flow is simple but powerful. We fetch raw samples from HealthKit, preprocess them into a prompt-friendly format, and feed them into a quantized Llama-3 model managed by the MLX framework. graph TD A[iPhone HealthKit Store] -->|Fetch HRV Samples| B(Swift Data Controller) B -->|Normalize & Format| C{MLX-Swift Engine} D[Llama-3-8B-4bit Model] -->|Load Weights| C C -->|Local Inference| E[Neural Engine / GPU] E -->|Semantic Summary| F[SwiftUI Dashboard] F -->|User Feedback| A Prerequisites 🛠️ To follow this advanced tutorial, you'll need: Xcode 15.4+ and a physical iPhone (iPhone 15 Pro or newer recommended for 8GB+ RAM). MLX-Swift : Apple's framework for machine learning on Apple Silicon. Llama-3-8B (4-bit quantized) : To fit within the iOS memory footprint. HealthKit Permissions : Configured in your Info.plist . Step 1: Accessing HealthKit Data 💓 First, we need to grab that juicy HRV data. Heart Rate Variability is a key indicator of autonomic nervous system stress. import HealthKit c

2026-07-24 原文 →
AI 资讯

I built SwiftNotch: a productivity dashboard for the MacBook notch

The notch on a MacBook is strange real estate. It is always there. It sits at the top of the screen, close to the menu bar, close to system controls, close to whatever you are doing. But most of the time it is treated like a cutout to design around instead of a place software can use. That felt like a missed opportunity. So I built SwiftNotch , a macOS menu bar app that turns the notch area into an expandable productivity dashboard. Hover near the notch or press Option + Space , and the quiet black shape becomes a small command center for widgets, files, media, shortcuts, developer tools, and window actions. Website: swiftnotch.xyz Demo video: Launch note: SwiftNotch 1.x is free during beta . I want early Mac users to try the full experience, share feedback, and help shape the app before SwiftNotch 2.0 introduces paid plans. The idea I did not want to build another large dashboard that asks you to leave your current app. The goal was the opposite: make useful tools available in the smallest possible space, without breaking flow. The notch is perfect for this because it already behaves like a visual anchor. You know where it is without thinking. If it can expand only when needed, it becomes a temporary interface layer instead of another permanent panel. SwiftNotch starts collapsed. When activated, it opens into a compact dashboard with the widgets and actions you choose. What SwiftNotch does The current app includes 31 built-in widgets across productivity, system utilities, media, automation, and developer workflows. Some examples: Media Control for Spotify, Apple Music, VLC, YouTube, and browser players Shelf for drag-and-drop file staging, quick sharing, paths, iCloud actions, and zip workflows Clipboard History for snippets, links, and quick paste Calendar Events , Reminders , Notes , Weather , World Clock , and Pomodoro Quick Toggles for Wi-Fi, Bluetooth, Dark Mode, and volume Window Snapping with layouts for halves, thirds, quarters, and custom grids Developer H

2026-07-23 原文 →
AI 资讯

I Got Tired of Hand-Translating Xcode Plists, So I Built a Tiny Free Tool to Do It On-Device

If you've ever localized an iOS or macOS app, you know the drill: you've got a .plist file full of UI strings sitting in Base.lproj , and now you need the same file in fr.lproj , th.lproj , de.lproj ... and so on for every language you support. You can pay for a translation service, hand it to a freelancer, or sit there manually retyping strings into fifteen copies of the same file. I didn't want to do any of those things, so I spent a day building pListTranslatorApp — a small SwiftUI macOS app that opens an Xcode plist, finds the string values you want translated, batch-translates them using Apple's built-in Translation framework, and writes out a ready-to-use localized plist. It's free, it runs entirely on-device, and it's now sitting on GitHub for anyone who wants it. The constraint that shaped the whole thing I'm developing on a MacBook Air with a 256GB SSD and 8GB of RAM — not a lot of headroom. That ruled out a couple of obvious approaches: Cloud translation APIs (DeepL, Google Cloud Translate, etc.) work well, but even a generous free tier means an external dependency, an API key to manage, and a network round-trip for something that's ultimately just short UI strings. Downloading a pile of on-device language models "just in case" eats real disk space fast — Apple's Translation framework models are shared system-wide across apps, which helps, but they still add up if you're not paying attention. So the app leans entirely on Apple's Translation framework , downloading exactly one language pack at a time, on demand, and lets you delete it once you're done with that language. What it actually does Open a plist. Pick any Xcode .plist via a standard file importer. Choose which keys to translate. Originally I hardcoded it to look for a key called itemTitle , but that's obviously too narrow for anyone else's project — so it's now a comma-separated text field. Type itemTitle, title, label and it'll pick up all of them, anywhere in the plist's nested dictionaries and

2026-07-19 原文 →
AI 资讯

Part 2 — Search, palette, and settings

Part 2 — Search, palette, and settings Level: Intermediate · Time: ~35 minutes · Builds on: Part 1 — Contacts app Part 1 got you shipping. This one gets you productive . We'll take the Contacts app and give it the ergonomics real users expect: an adaptive sidebar that becomes a tab bar on iPhone, a command palette on ⌘K, honest loading states while data comes in, and a proper settings screen. Zero #if os guards. Zero re-rolled controls. What we're adding An adaptive shell — DFSidebar on regular width, DFTabBar on compact. A search field at the top of the list, filtering as you type. A ⌘K command palette exposing every action in the app. Skeleton loaders for a simulated slow fetch. A settings screen — notifications toggle, density picker, sync-interval slider, pinned-since date picker, beta-features checkbox. Per-component token overrides on the settings screen, without forking the theme. 1. Shell: sidebar on wide, tab bar on narrow The routing decision — sidebar vs tab bar — should be data, not a view hierarchy. Enumerate your sections once, then feed the two components the shapes they want. API note. DFSidebar uses Binding<String?> and is just the sidebar view — you compose the detail pane yourself (naturally via NavigationSplitView ). DFTabBar uses Binding<String> (non-optional) and does take a content builder that receives the selected ID. Both use plain String IDs, so we keep a simple Section enum and pass rawValue at the boundary. enum Section : String , CaseIterable , Identifiable , Hashable { case contacts , favorites , archive , settings var id : String { rawValue } var label : String { switch self { case . contacts : "Contacts" case . favorites : "Favorites" case . archive : "Archive" case . settings : "Settings" } } var icon : String { switch self { case . contacts : "person.2.fill" case . favorites : "star.fill" case . archive : "archivebox.fill" case . settings : "gear" } } static func from ( _ id : String ?) -> Section { id . flatMap ( Section . init (

2026-07-18 原文 →
开发者

I built a native macOS database GUI because I was fed up with TablePlus limits

I've been using TablePlus for years. It's good — but the connection limits on older licences drove me mad, and most alternatives are either Electron apps or haven't been updated since 2019. So I built my own. What is Stratum? Stratum is a native macOS database GUI — written in Swift, not wrapped in Electron. It connects to MySQL, MariaDB, PostgreSQL, and SQLite. What made me actually build it Three things: 1. Connection limits. TablePlus caps connections on older licences. Stratum has none. 2. Electron alternatives. Beekeeper Studio is good but it's an Electron app. On a Mac, that matters. 3. The MySQL setup friction. Most tools require you to install extra dependencies. Stratum connects natively — no brew install, no extra setup. What it does Table browser with inline editing — add, edit, delete rows without SQL Server-side pagination — stays fast on tables with 100k+ rows Query editor with schema-aware autocomplete Visual schema designer — create tables, add columns without writing DDL Full SQL export — DROP + CREATE + batched INSERTs iCloud sync for connections and snippets Laravel Valet auto-detection Import connections from TablePlus in one click SSH tunnelling The tech Built with SwiftUI and Swift 6. The PostgreSQL driver uses PostgresNIO. The MySQL driver implements the MySQL wire protocol directly over Network.framework — no Homebrew dependency, works inside the App Sandbox. Where it is now Currently in free beta. One-time purchase planned for the Mac App Store — no subscription. → stratum.mwn-digital.uk Happy to answer questions about how it's built.

2026-07-17 原文 →
AI 资讯

Every Third-Party iOS Keyboard Is a Graveyard. So I Built a Voice Keyboard From Scratch in C++.

If you've searched the App Store for a reliable third-party QWERTY keyboard on iOS, you know how that ends. Some are abandoned. Some are ad-riddled. Some feel like they were ported from Android and never touched again. The good ones are the ones that don't ship features so much as they don't crash. The system keyboard is fine. It's fine because Apple has been iterating on it for fifteen years. Nobody else has. Third-party keyboards on iOS are a graveyard. I'm building one that isn't. It's called Diction. Most people know it as a voice keyboard, and that's what I lead with, but under the hood it's a serious low-level QWERTY project too. This post is about that half of it, because that's the half nobody talks about. Why third-party QWERTY on iOS is a graveyard Building a good keyboard extension on iOS is hard. There's a strict memory ceiling. There's a permission dance the user has to opt into. There's no keychain access, no meaningful background work, and the extension can be killed the moment iOS decides it needs the RAM. Most keyboard makers ship a first version to check the box, then abandon it once they see how much work maintaining it takes. The result is what you see on the App Store today. Every third-party keyboard I've tried on iOS fails on at least one of these: Speed. You type a letter, the letter arrives. That's it. If there's a hitch you can feel, the keyboard is broken. Half the ones I've tried have a visible delay on every keystroke. Predictability. If you correct the same word back three times, that word should be yours. The keyboard should stop fighting you. Most never do. You fight the same wrong correction for a year. Recovery. iOS keyboard extensions are memory-constrained. Bad ones freeze under pressure. When you rapid-switch between apps, half the third-party keyboards on the store will lock up until you kill and reopen the host app. Autocorrect that isn't from 2014. Fix the obvious typos. Split words that ran together. Complete contractions. Ge

2026-07-15 原文 →