$ grep -r Tag: «swift»

-rw-r--r-- 7.0K May 19, 2026 · CE824A9 · ~5 min

Swift Adwaita: from 1.2.0 to 1.3.1

swift libadwaita open source swift package linux macos

After the 1.1.0 release, the swift-adwaita library has shipped seven releases in a row. As I keep working on the first real application built with this wrapper, things keep surfacing that synthetic tests never catch — and almost every fix in this cycle came from there. The headline story: swift-adwaita now builds and runs on macOS, and along the way I stepped on a beautiful set of rakes involving Swift Concurrency inside the GLib main-loop, and carefully stepped back off.

Swift Adwaita

The story of a bug: async that never runs

In 1.2.0 I collapsed all dialogs (FileDialog, ColorDialog, FontDialog) onto async throws and dropped the callback variants — felt cleaner that way. A day later it turned out that inside a running GTK application (g_application_run), code like Task { @MainActor in await dialog.open(...) } simply never executes. Swift's default main-actor executor is DispatchQueue.main, and the GLib main-loop doesn't drive it. The process looks alive, no errors surface, the button clicks — but the file dialog never appears.

1.2.1 urgently restored the callback variants for FileDialog, and 1.2.2 closed the hole completely: callback overloads were added for every async API (Clipboard, ColorDialog, FontDialog, UriLauncher, Texture.load). The async variants stay — they're useful for tests and non-GTK contexts — but inside GTK signal handlers the callback form is now the recommended default. The long-term fix (a custom SerialExecutor on top of GLib) is deferred as a separate task.

1.2.0: what landed in the API

  • Async image loading. Texture.load(from:) decodes anything GdkPixbuf supports — PNG, JPEG, GIF, WebP, TIFF, BMP — off the main actor. That's a superset of what the native gdk_texture_new_from_filename handles.
  • Animated image playback. AnimatedImagePlayer drives frames from a GdkPixbufAnimation into a Picture widget, with start / stop / advanceFrame.
  • Application.onOpen and Application.run(arguments:) — file-open activation for apps registered with the G_APPLICATION_HANDLES_OPEN flag.
  • Runtime widget type checks. Widget.gtkType, isInstance(of:), and a stricter tryCast that now actually narrows the type instead of "successfully" casting any widget to anything.
  • Isolated deinits on GObjectRef, GVariant and other wrappers — GObject release now always happens explicitly on the main actor, not on whichever random thread dropped the last reference.
  • Minimum toolchain bumped to Swift 6.2 — isolated deinit is experimental in 6.1, and the release toolchain refused to enable it.

1.2.3–1.2.5: conveniences and clipboard

Three small releases about reaching for CAdwaita less often for routine things:

  • RGBA(hex:) — CSS color parsing: #RGB, #RGBA, #RRGGBB, #RRGGBBAA.
  • IconTheme — a wrapper around gtk_icon_theme_get_for_display with addSearchPath(_:) for app-local icons.
  • ApplicationFlags as an OptionSet: Application(id: "...", flags: [.handlesOpen, .nonUnique]) instead of raw bit masks.
  • MainContext.drainPending() and pump(for:) — one-line replacements for the while g_main_context_pending { g_main_context_iteration } loop that every test suite kept reinventing.
  • Paste interception. Widget.onPasteClipboard, the synchronous Clipboard.containsImage / containsFiles probes, async readTexture / readFiles, and Texture.encodedPNGData() — you can now intercept a pasted image in your editor and pipe it through your own import path, instead of letting GTK shove it in as text.
  • Silencing GTK-CRITICAL spam from GtkScrolledWindow and misconfigured GtkDropTarget — an opt-in log filter plus the correct signatures for the ::enter / ::motion signals.

1.3.0: macOS as a development platform

The main news of the cycle. swift-adwaita now builds and runs on macOS 13+ on Apple Silicon. Linux remains the primary target platform, but you can now develop and test locally on a Mac without spinning up a VM.

  • Install via Homebrew: brew install libadwaita gtksourceview5 pkgconf adwaita-icon-theme. Without adwaita-icon-theme, HeaderBar buttons and banners render empty — Homebrew doesn't pull it in transitively.
  • Required environment variable: XDG_DATA_DIRS=/opt/homebrew/share, otherwise libadwaita can't find its GSettings schemas and aborts at startup.
  • DemoAppLib — all 78 gallery examples now live in a separate library that downstream apps can link against directly. The DemoApp executable became a three-line shim.
  • Xcode example in examples/macos/DemoApp/ — a minimal Xcode 16+ project that wraps the gallery as a regular .app bundle. Cmd+R, and it works.
  • A parallel XCTest suite for macOS. swift-testing on Apple platforms inserts autorelease-pool transitions between tests that conflict with the Cocoa CFRunLoop sources installed by gtk_init — everything aborts on the second test. XCTest doesn't do that, and the same coverage runs there. Linux keeps using swift-testing. Result: 1181 tests / 0 failures on macOS.
  • Three Apple-specific bugs that Linux/glibc happened to mask: Variant.stringValue returned nil for valid strings (a dangling pointer through g_variant_type_checked_); the localization helpers (localized, nlocalized) returned garbage when no translation was available (gettext returns the input pointer untouched, and the Swift→C bridge had already freed it); MediaStream.timestamp failed to compile because gint64 is long on Linux x86_64 but long long on Apple arm64.
  • macOS CI job on macos-26 with Xcode 26.4.1 (Swift 6.3). Build only, no test runs: GitHub-hosted runners are headless, and GTK4-Quartz crashes without a WindowServer session.
  • REUSE 3.3 license metadata — SPDX headers in every source file, reuse lint reports clean.

1.3.1: cleanup

A maintenance release with no API changes. I polished the paste-interception docs in the README, added adwaita-icon-theme to every macOS install snippet (stepped on it, wrote it down), and bumped the Xcode example's deployment target to macOS 26 so it matches what Homebrew now builds GTK4 against — otherwise the linker complains about every dylib.

What's next

The big unsolved problem is still the Swift Concurrency ↔ GLib main-loop integration. Right now you can't write Task { @MainActor in ... } from a click handler in a GTK app, and that's frustrating. The long-term plan is a custom SerialExecutor that routes work through g_idle_add_full instead of DispatchQueue.main. The callback APIs cover every practical scenario today, but a proper executor will need to be written eventually.

The project is open source under the MIT license. The source lives on GitHub, and the documentation with guides is here.

Star Fork

[↵] open page swift-adwaita-from-1-2-0-to-1-3-1.md
-rw-r--r-- 1.7K Apr 10, 2026 · 1F1DDF3 · ~2 min

Swifty Notes - a markdown notes manager for Linux in Swift

swift libadwaita open source linux

Swift Notes for Linux

After shipping swift-adwaita, I've been focused on building a first app using it. Something simple, but handy for myself. So now the first app has been shipped.

Swifty Notes is a native GTK/libadwaita Markdown notes application for Linux written in Swift.

The desktop app is the primary experience: write, organize, and preview Markdown notes with native GTK widgets, autosave, remembered workspace state, and adjustable editor settings such as font size, wrapping, indentation, and appearance.

The included CLI works on the same file-backed notes so shell scripts, automation, and AI agents can safely inspect or update notes without a separate database or background service.

  • Create, rename, duplicate, export, and delete Markdown notes.
  • Autosave edits, remember workspace state, and keep note-local image assets together with each note.
  • Adjust editor font size and other writing preferences to fit different screens and workflows.
  • Choose where notes are stored, including a cloud-synced folder, so the same plain files can stay in sync across devices.
  • Import images with drag and drop and render Markdown with a native GTK preview instead of a web view.
  • Use the CLI for JSON-friendly note automation from scripts, shell pipelines, and AI agents.

Get it on Flathub

Swifty Notes for Linux is an open source project, source code is available on GitHub.

Star Fork

[↵] open page swifty-notes-a-markdown-notes-manager-for-linux-in-swift.md
-rw-r--r-- 3.1K Apr 10, 2026 · D872E75 · ~2 min

Swift Adwaita 1.1.0

swift libadwaita open source swift package linux

Swift Adwaita

Swift Adwaita 1.1.0 has been released. I’ve been working on a first app built with this library, so I’ve extended it and fixed some bugs.

Highlights

  • Added GtkSourceView integration with typed Swift wrappers for source editing, syntax highlighting, languages, and style schemes.
  • Expanded widget APIs around popovers, windows, calendar compatibility, and runtime lifecycle handling.
  • Improved release stability with better GLib main-loop integration, broader CI coverage, and additional regression tests.

Added

  • SourceView, SourceBuffer, SourceLanguage, SourceLanguageManager, SourceStyleScheme, and SourceStyleSchemeManager.
  • Typed identifiers for GtkSource languages and style schemes.
  • A new source editor demo example.
  • MainContext.task { ... }, task(after:), and task(every:) as cancellable GLib main-loop work handles.
  • Async MainContext.run, yield, and sleep(for:) helpers for bridging Swift concurrency onto the GLib loop safely.
  • Widget.unparent() and PopoverMenu.unparent().
  • Convenience presentation helpers for Popover and PopoverMenu.
  • Additional regression tests for widget/window parent-chain lookup and expanded coverage for source editing and media behavior.

Changed

  • GtkWindow.present() now retains windows until close, making transient or locally scoped windows safer to use.
  • Widget.window now resolves the containing window through the widget parent chain instead of assuming the GTK root is always a window.
  • Calendar date handling now uses a GTK compatibility shim so the package builds cleanly across older and newer GTK versions.
  • Documentation generation and hosted docs configuration were updated.
  • CI now installs and tests with GtkSourceView 5 system dependencies.

Fixed

  • Fixed deferred signal/user-data cleanup to release captured closures through the GLib main loop instead of Swift main-queue tasks, avoiding lifecycle issues in GTK applications.
  • Fixed a common GTK scheduling pitfall by offering a Task-like API that stays on the GLib main loop instead of DispatchQueue.main.
  • Fixed Swift 6.1 serialized suite visibility issues in the test suite.
  • Fixed the popover/window regression tests to avoid GTK crash paths in CI while still validating the intended behavior.
  • Fixed release documentation and installation instructions to include GtkSourceView 5 development packages.

Documentation and CI

  • Added an API documentation link to the README.
  • Updated installation instructions for Ubuntu/Debian and Fedora.
  • Improved inline documentation consistency across the wrapper API.
  • Extended CI coverage for documentation, formatting, and Swift 6.1 / 6.2 / 6.3 test runs.

This is an open-source project licensed under the MIT license. The source code is available on GitHub. Documentation with guides is available here.

Star Fork

[↵] open page swift-adwaita-1-1-0.md
-rw-r--r-- 1.4K Mar 31, 2026 · 6420B81 · ~1 min

Swift Adwaita library

swift libadwaita open source swift package linux

Swift Adwaita

A project that I’ve always wanted to create: a library that enables the development of GNOME applications using Swift. While there are some similar libraries available, they appear to be incomplete or not actively maintained. Thanks to Vibe Coding, I managed to complete the project in approximately a week.

swift-adwaita is an imperative Swift 6 wrapper for GTK4 and libadwaita, built for creating native GNOME desktop applications on Linux.

It provides a modern Swift API over GTK and Adwaita with type-safe widgets, signals, property bindings, async operations, and ergonomic convenience helpers, while preserving the native behavior, styling, and feel of the GNOME platform.

  • Native GTK4 and libadwaita application development in Swift
  • Imperative API without a custom DSL
  • Type-safe enums, signals, and property APIs
  • Async/await support for common platform integrations
  • Extensive widget coverage with a real demo application

Here’s a demo app built using swift-adwaita:

This is an open-source project licensed under the MIT license. The source code is available on GitHub. Documentation with guides is available here.

Star Fork

[↵] open page swift-adwaita-library.md
-rw-r--r-- 2.3K Mar 28, 2026 · 506D0D0 · ~2 min

CouchDB client for Swift 2.4.0

swift couchdb swift package vapor open source

Highlights

  • Refactored the internal request pipeline in CouchDBClient to use cleaner async/await-style flows and reduce duplicated response handling logic.
  • Improved buffering and decoding paths for raw and typed requests, with a focus on safer EventLoopGroup execution and better performance in response processing.
  • Expanded test coverage around EventLoopGroup-backed request execution, including raw and typed get, raw and typed find, attachment download, Mango index listing, and Mango query explanation.
  • Refreshed user-facing documentation across the README, DocC articles, and tutorials.
  • Updated documentation tooling for newer DocC workflows, including Markdown export support.

API and Behavior Improvements

  • Added and refined EventLoopGroup support across more CouchDBClient request paths.
  • Improved internal error-handling paths and response decoding behavior for CouchDB operations.
  • Simplified request helper layering and reduced duplicated request/response processing code.
  • Improved attachment-related behavior and accompanying tests.
  • Added visionOS to supported platforms in the package manifest.

Documentation

  • Fixed and refreshed README examples for CRUD and Mango query usage.
  • Updated DocC landing pages to better reflect the current API surface.
  • Corrected the Advanced Mango Query tutorial snippets to match the current typed query API.
  • Corrected Vapor tutorial examples.
  • Fixed Hummingbird tutorial package setup and dependency snippets.
  • Updated buildDocs.sh to support:
    • configurable output and hosting base path
    • static hosting content embedding
    • experimental Markdown output
    • Markdown manifest generation
  • Added a post-processing step in buildDocs.sh that injects a relative Markdown link into generated DocC HTML pages.

Tooling and Dependencies

  • Updated package dependencies in Package.resolved.
  • Updated the Ubuntu build workflow Swift version matrix.

CouchDB Client on GitHub | Documentation with examples and tutorials.

Star Fork

[↵] open page couchdb-client-for-swift-2-4-0.md
-rw-r--r-- 1.3K Aug 1, 2025 · 508C136 · ~1 min

CouchDB client for Swift 2.3.0

swift couchdb swift package vapor open source

CouchDB client for Swift 2.3.0

Recently, I've implemented a feature that I wanted to add to the CouchDB Swift client for a long time. It's Mango Queries support. Finally, it is done in 2.3.0. Feels like the last remaining big feature.

Changelog:

  • Introduced a robust and type-safe MangoQuery API for building complex selectors, projections, sorting, and pagination in CouchDB.
  • Added support for specifying indexes via useIndex in queries to optimize performance.
  • Added first-class support for uploading, downloading, and deleting document attachments (files/images).
  • Comprehensive Attachments API test suite ensures reliability for file operations.
  • Added models and API for creating, listing, and managing Mango indexes (MangoIndex, IndexDefinition).
  • Tutorial and code samples for creating indexes are now included in documentation.
  • Added support for CouchDB Mango _explain endpoint via MangoExplainResponse to inspect how queries are executed and which indexes are used.

CouchDB Client on GitHub | Documentation with examples and tutorials.

Star Fork

[↵] open page couchdb-client-for-swift-2-3-0.md
-rw-r--r-- 1.4K Jul 31, 2025 · 043C479 · ~2 min

A story of one bug in Leaf

swift vapor leaf open source

A story of one bug in Leaf

This website is working on Vapor - a server-side Swift framework. It's pretty old, popular, and well known.

I’ve used it for a few years already and always liked that it's fast and doesn't require a lot of memory on the server.

I'm keeping all dependencies up to date. But recently I've noticed that the website started to eat a lot of memory. It starts with about 20 mb of memory usage, but after a few weeks, I found that it ate about 750 mb on the server.

That's a lot for such a simple website, so I started digging. After reviewing the site code (which I didn't change for a long time), I couldn't find any issues (and AI agents too).

I use Leaf - a template engine from the Vapor team to render HTML. And there was an open issue on their GitHub repo describing exactly the same problem.

So I've asked Copilot to help me debug what's wrong. Pretty quickly, it added some new tests to my fork that did a lot of renders in a cycle. And leak util found retain cycles. So I fixed that with some weak annotation, but during the review of my PR, a maintainer suggested to just use unowned.

And that's it. 2 lines of code fixed memory growth. It's hard to believe, but after a few hours since the deploy, the website still takes only 2 mb of memory. So I'm very proud of myself today.

Morale: contribute to the open-source project that you use.

[↵] open page a-story-of-one-bug-in-leaf.md
-rw-r--r-- 471B Jul 10, 2025 · A43AF6A · ~1 min

A Swift package for spell checking using Yandex.Speller

swift open source yandex speller

A Swift package for spell checking using Yandex.Speller

For my own purposes, I wanted to add a spell checker to one of my apps. It should check the text and automatically correct it. Built-in macOS writing tools work fine for English, but don’t work for Russian.

So after it's done, why not share it?

https://github.com/makoni/YaSpellChecker

[↵] open page a-swift-package-for-spell-checking-using-yandex-speller.md
-rw-r--r-- 1.8K Jul 8, 2025 · 931C7C2 · ~2 min

Recent updates of my projects

swift couchdb app store release informer open source ai

Recently, I've been playing a lot with AI agents, and it really inspired me to update my projects. Playing with real-life tasks makes it more fun.

Couchdb Swift client lib

There are 2 new releases of couchdb-swift library. Copilot kindly added more unit tests to the library to cover more use cases. Mostly failures. I still had to tweak a lot manually, but it gave me some ideas. So I've added more error handling in these 2 recent releases. Also, it found a couple of minor bugs and fixed them, reviewed my PR, and suggested some improvements. Far from being perfect yet, but still pretty impressive.

Release Informer Bot for Telegram

At some moment, I found that Copilot Agent is available for my account, and I can simply start with an issue on GitHub, assign it to the agent, and see what it will do. I've started with a request to update the README for Release Informer Bot with some nice details about how it works and how to set it up.

After the agent finished the updated README, it gave me another idea. Setting up might be automated. So I've opened Visual Studio Code and asked the Copilot agent to add automatic creation of the required database and set it up with the required CouchDB indexes.

It also did a good job, but it still required some manual tweaks and changes. And during that, it led to one more release of the CouchDB client lib because I wanted to rely on a proper "not found" error.

It's hard to tell how much time Copilot saved me. But definitely a lot. Including my favorite automatic string translations. Hopefully, that will inspire me to ship more.

[↵] open page recent-updates-of-my-projects-july-2025.md
-rw-r--r-- 1.2K Apr 16, 2025 · B2756B3 · ~1 min

CouchDB client for Swift version 2

swift couchdb swift package vapor open source

CouchDB client for Swift version 2

Recently, I’ve released a few new versions of the CouchDB client for Swift. The latest version is version 2, and it includes several key changes:

  • Updated the minimum required Swift tools version to 6.0.
  • Adopted Swift Concurrency. CouchDBClient has been updated to be an actor.
  • Renamed the library from couchdb-vapor to couchdb-swift to better reflect its purpose as a general CouchDB client for Swift, beyond Vapor-specific use cases.
  • Made some changes to the initializer. Instead of passing a lot of parameters, it now accepts a Config structure.
  • You can pass your own HTTPClient instance to be used in the client.
  • Added translations for error messages.
  • Introduced a dedicated tutorial for integrating CouchDBClient with the Hummingbird server-side framework.
  • Added a shutdown() method to properly release resources associated with the HTTPClient.

CouchDB Client on GitHub | Documentation with examples and tutorials.

Star Fork

[↵] open page couchdb-client-for-swift-version-2.md
-rw-r--r-- 1.2K Apr 8, 2024 · BA68FE9 · ~1 min

Swift CouchDB client 1.5.0

swift couchdb swift package vapor open source

Swift CouchDB client 1.5.0

And here we go, one more new version of the CouchDB client library. After the recent post about 1.4.0, Swift on Server released a new version of async-http-client that includes a new implementation of the client singleton. Now it's HTTPClient.shared, so I've updated the CouchDB library to adopt that change. This also means that you no longer need to call httpClient.syncShutdown() if the singleton is used. Additionally, they've bumped the minimum Swift version to 5.8 (which I aslo did in version 1.4.0 of the CouchDB client library). So, I'm keeping the library up to date.

Changelog:

  • Bumped the minimum version of async-http-client to the new 1.21.0. If you can't use it in your project, you can still stay on 1.4.0.
  • The library will now use HTTPClient.shared (new in async-http-client 1.21.0) internally for requests if no EventLoopGroup is provided.
  • No more internal calls for httpClient.syncShutdown() in case of HTTPClient.shared usage.

CouchDB Client on GitHub | Documentation with examples and tutorials.

[↵] open page swift-couchdb-client-1-5-0.md
-rw-r--r-- 1.2K Apr 8, 2024 · 08DA6BF · ~1 min

Swift CouchDB client 1.4.0

swift couchdb swift package vapor open source

Swift CouchDB client

A new version of CouchDB Client has been released:

  • The library migrated from HTTPClient.Response to HTTPClientResponse, which is similar to HTTPClient.Response but used for the Swift Concurrency API. It also migrated from HTTPClient.Body to HTTPClientRequest.Body. These changes impact the get and find methods. Old methods are marked as deprecated, please refer to the documentation for the updated methods.
  • The minimum Swift version is now 5.8.
  • The CouchDBRepresentable protocol is now marked as Codable.
  • Additionally, a new data model called RowsResponse has been added. It accepts a generic CouchDBRepresentable type, making it easier to retrieve rows from a database. For example:
    let decodeResponse = try JSONDecoder().decode(RowsResponse<MyApp>.self, from: data)
  • Lastly, there have been small improvements in the documentation and tutorials.

CouchDB Client on GitHub | Documentation with examples and tutorials.

[↵] open page swift-couchdb-client-1-4-0.md
-rw-r--r-- 1.1K Apr 4, 2024 · 0427246 · ~1 min

A middleware for Vapor 4 routing to trim a slash in url path

vapor code snippets шпаргалки swift server side swift

It’s a common thing for a website or a backend to allow URLs like mySite.com/webpage and mySite.Com/webpage/ for the same page. These pages are different URLs for a search engine. If you want to avoid duplicates, you can add a simple middleware to trim the ending slash and redirect a user.

Here’s an example code for such a middleware class for Vapor 4:

final class TrimSlashInPathMiddleware: Middleware {
    func respond(to request: Request, chainingTo next: Responder) -> EventLoopFuture<Response> {
        if request.url.path.count > 1, request.url.path.hasSuffix("/") {
            let newPath = String(request.url.path.trimmingSuffix(while: { $0 == "/" }))
            let response = request.redirect(to: newPath, redirectType: .permanent)
            return request.eventLoop.makeSucceededFuture(response)
        }
        return next.respond(to: request)
    }
}

Just add it to configure.swift file:

import Vapor

public func configure(_ app: Application) throws {
    app.middleware.use(TrimSlashInPathMiddleware())

    app.http.server.configuration.port = 8081

    try routes(app)
}

Works with Vapor 4.92.5.

[↵] open page a-middleware-for-vapor4-to-trim-a-slash-in-url-path.md
-rw-r--r-- 836B Mar 29, 2024 · EA452FF · ~1 min

Swift CouchDB client 1.3.2

swift couchdb swift package vapor open source

Swift CouchDB client

Recently, there have been a couple of new releases for my Swift CouchDB library. Here are the recent changes:

  • dateDecodingStrategy and dateEncodingStrategy can now be passed as parameters for get, update and insert methods.
  • Added a check to handle expired authentication cookies.
  • Comparing the set-cookie header in the response as lowercased.
  • Introduced new methods to utilize the _find API, allowing you to find documents using a declarative JSON querying syntax
  • Fixed an issue where the update method didn’t use dateEncodingStrategy parameter.

CouchDB Client on GitHub | Documentation with examples and tutorials.

[↵] open page swift-couchdb-client-1-3-2.md
-rw-r--r-- 973B Dec 26, 2022 · BE2067B · ~1 min

Swift CouchDB client 1.2.1

swift couchdb swift package vapor open source

Swift CouchDB client 1.2.1

Just a small update for Swift CouchDB client lib with couple new methods that I needed by myself:

  • Added a new method to create a database [docs].
  • Added a new method to delete a database [docs].
  • Added a new method to check if a database exists [docs].
  • Every request handles unauthorised errors now.
  • CouchDBClientError model has a description text now.

CouchDB Client on GitHub | Documentation with examples and tutorials.

[↵] open page swift-couchdb-client-1-2-1.md
-rw-r--r-- 1.1K Oct 4, 2022 · A996DD3 · ~1 min

Swift CouchDB client 1.2.0

swift couchdb swift package vapor open source

Swift CouchDB client 1.2.0

Couple months ago I started learning Apple's DocC tool that generates documentation from your source code. I've decided to use as many features as possible so I took my small lib CouchDB Client and added docs to every method including usage examples that Xcode will show in the autocomplete popup. As it often happens, during adding docs and examples I found that many things in the library can be done in a much better way. So I've updated existing methods and added some more that can take a doc as a param and use generic types.

Next step was tutorials. Apple allows devs to create exactly the same tutorials as they have for SwiftUI on their own website. So I've added a couple. They're also part of the repo on GitHub.

Pretty sure that I've spent more time on the documentation than on the lib itself but I hope it's worth it.

CouchDB Client on GitHub | Documentation with examples and tutorials.

[↵] open page swift-couchdb-client-1-2-0.md
-rw-r--r-- 1.5K Mar 29, 2020 · C1C7EDD · ~1 min

Wrapping models in SwiftUI for Identifiable conformance

swiftui swift шпаргалки

Using an array of models in List view in SwiftUI requires conformance to Identifiable protocol.

Here's an example of a model:

struct MyDataModel {
    let title: String
    let message: String
} 

An example of SwiftUI view that you want to display a list:

struct TestView: View {
    var dataArray: [MyDataModel]
    var body: some View {
        List(dataArray) { data in
            VStack {
                Text(data.title)
                Text(data.message)
            }
        }
    }
} 

Using MyDataModel in List will show an error in Xcode:

Xcode Identifiable conformance error

Sometimes you can't just change a model. It might be a data model from a third party SDK that you're using in your app. But you can create a wrapper for this struct to confirm Identifiable protocol:

struct MyDataModelWrapper: Identifiable {
    var id = UUID()
    var data: MyDataModel
}

let testDataModel = MyDataModel(
    title: "Title 1",
    message: "I wanna be used inside of a List"
)

let wrappedData = MyDataModelWrapper(data: testDataModel)

So the view will look like this:

struct TestView: View {
    var dataArray: [MyDataModelWrapper] 

    some View {
        List(dataArray) { wrappedData in
            VStack {
                Text(wrappedData.data.title)
                Text(wrappedData.data.message)
            }
        }
    }
}

Done.

[↵] open page wrapping-models-in-swiftui-for-identifiable-conformance.md
-rw-r--r-- 956B Sep 23, 2019 · B28AFA6 · ~1 min

Syntax sugar for JSON parsing in Swift

swift swift package json open source

JSON decoding and encoding became easy after adding Codable protocol in Swift 4.0. But during coding I wanted to have something shorter and more elegant than Do-Catch statement that looks like this:

var myModel: MyModel?
let decoder = JSONDecoder()

do {
    myModel = try decoder.decode(MyModel.self, from: data)
} catch {
    print(error.localizedDescription)
}

Or like this:

let myModel: MyModel? = try? decoder.decode(MyModel.self, from: data)

So I wrote a protocol with default implementation that allows to do decoding just like that:

let myModel = MyModel.decodeFromData(data: data)

And the same for encoding:

let data = MyModel.encode(fromEncodable: myModel)

All you need is just to add protocol conformance:

extension MyModel: Parseable {
    typealias ParseableType = Self
}

It's available on GitHub as a Swift Package: https://github.com/makoni/parsable

[↵] open page syntax-sugar-for-json-parsing-in-swift.md
-rw-r--r-- 956B Sep 10, 2019 · 64BE02E · ~1 min

Using GitHub Actions as a CI for Swift project

swift github ci шпаргалки

Github Actions

Here's a config for a GitHub Actions workflow to build a Swift project. This example is for building a Vapor project using Swift 5.0.3 on Ubuntu 18.04:

name: Ubuntu 18.04 Swift 5.0.3

on: [push]

jobs:
  build_on_ubuntu:
    runs-on: ubuntu-18.04

    steps:
    - name: Install dependencies
      run: sudo apt-get update; sudo apt-get install -yq libssl-dev zlib1g-dev

    - name: Checkout
      uses: actions/checkout@master

    - name: Download Swift
      run: curl https://swift.org/builds/swift-5.0.3-release/ubuntu1804/swift-5.0.3-RELEASE/swift-5.0.3-RELEASE-ubuntu18.04.tar.gz --output swift.tar.gz

    - name: Unpack Swift
      run: |
          tar xzf swift.tar.gz
          mv swift-5.0.3-RELEASE-ubuntu18.04 swift

    - name: Swift build
      run: |
          export PATH=$(pwd)/swift/usr/bin:"${PATH}"
          swift build -c release
[↵] open page using-github-actions-as-ci-for-building-swift-project.md
-rw-r--r-- 1.0K Oct 1, 2018 · 66FB865 · ~2 min

Benchmarks: Vapor 3 vs. Vapor 2

swift backend vapor ubuntu benchmark

After migrating (almost rewriting) my small project from Vapor 2 to Vapor 3 I've run benchmarks to compare performance. I didn't run benchmarks for the last version of Vapor 2.x so I will compare Vapor 2.1.0 to results of Vapor 3.1.0.

My server configuration:

  • 2 GB RAM
  • 1 CPU Core
  • SSD
  • 125 MBPS Out
  • Ubuntu 16.04.2 LTS
  • CouchDB

Benchmark from other server has been launched as:

wrk -t4 -c20 -d5m https://my_url

API just gets some data from CouchDB and returns it as JSON. Vapor project has been compiled with Swift 4.2.

[↵] open page benchmarks-vapor-3-vs-vapor-2.md
-rw-r--r-- 6.4K Nov 24, 2017 · 210FD78 · ~5 min

Animating the UISlider Thumb on Touch

swift ios полезное uislider

Animating the UISlider Thumb on Touch

I had a task to animate the slider in the app on touch by smoothly enlarging the thumb. Just like Apple does in the Apple Music and Podcasts player when you start scrubbing the playback position. I spent quite a lot of time looking for a way to do it with standard tools. I really did not want to write a completely custom slider; I wanted to use the system UISlider, and in the end I managed to do exactly that.

[↵] open page animatsiya-kasaniya-indikatora-v-uislider.md
-rw-r--r-- 374B Sep 5, 2017 · E5E50B4 · ~1 min

openssl and Vapor 2

vapor swift шпаргалки

I ran into a problem where a Vapor 2 project stopped compiling on Ubuntu. More precisely, one of its dependencies, Crypto. It turned out that because of an added repository containing newer versions of some libraries, it would not compile. Writing it down here — I had to downgrade:

apt install libssl-dev=1.0.2g-1ubuntu4.10
apt install openssl=1.0.2g-1ubuntu4.10
[↵] open page openssl-i-vapor-2.md
-rw-r--r-- 919B Jun 14, 2017 · 5C60537 · ~2 min

Benchmarks: Vapor 2 vs. Vapor 1

swift backend vapor ubuntu

After migrating my pet project from Vapor 1 to Vapor 2 I've run benchmarks to compare performance. I didn't run benchmarks for the last version of Vapor 1.x which is 1.5.15 so I will compare Vapor 2.1.0 to results of Vapor 1.2.5 that I have from my last results.

My server:

  • 2 GB RAM
  • 1 CPU Core
  • SSD
  • 125 MBPS Out
  • Ubuntu 16.04.2 LTS
  • CouchDB

Benchmark from other server was launched as:

wrk -t4 -c20 -d5m https://my_url

API just gets some data from CouchDB and returns it as JSON. Vapor project has been compiled with Swift 3.1.1.

[↵] open page benchmarks-vapor-2-vs-vapor-1.md
-rw-r--r-- 1.8K May 3, 2017 · 6BC24C7 · ~2 min

Weak delegate in Swift 3

swift шпаргалки утечки памяти

Memory usage in Xcode

I was fighting memory leaks in a work project. Digging led me to the fact that after leaving a UIViewController, far from all memory gets released. If you open this UIViewController several times, go back, and open it again, memory consumption grows and does not get released very much.

The root of the problem turned out to be protocols and delegates. A classic mistake. In my UIViewController I use a UICollectionView with a custom cell that has a delegate. My UIViewController is the delegate for each cell. An example of implementing such a protocol and delegate on the internet and in a Swift book looks roughly like this:

// Protocol
protocol MyCollectionViewCellDelegate {
    func someFunc()
}

// UICollectionViewCell
final class MessageCollectionViewCell: UICollectionViewCell {
    var delegate: MyCollectionViewCellDelegate?
}

// UIViewController
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    // some code....
    cell.delegate = self
}

Inside the cell object we have a strong reference to the delegate (UIViewController), which results in a memory leak.

The solution is simple — make the reference to delegate weak. To do that, you have to specify that only a class can implement the protocol. Structures are out, but there is no need for them here anyway. It changes like this:

// Protocol
protocol MyCollectionViewCellDelegate: class {
    func someFunc()
}

// UICollectionViewCell
final class MessageCollectionViewCell: UICollectionViewCell {
    weak var delegate: MyCollectionViewCellDelegate?
}

After these simple changes everything became great — after navigating back from the UIViewController, memory usage returns to its initial level.

[↵] open page weak-delegate-v-swift-3.md
-rw-r--r-- 1.1K Feb 9, 2017 · F3580BC · ~1 min

Space In Box Website

swift приложения space in box vapor

Space In Box website

I decided to move the information about my apps from apps.arm1.ru to a separate domain. Since I once started publishing them under the name Space In Box, the domain matches: spaceinbox.me. I decided to remove apps that were no longer relevant or available and use vector graphics as much as possible everywhere (icons, logos), because on Retina screens raster graphics really hurts the eyes.

It was a great excuse to build something in Swift with the Vapor framework, and so far everything I needed worked out. Updating it when something changes in the logic is of course harder, because you have to rebuild everything on the server each time, and that takes 3–4 minutes every time. But if it concerns only the layout (tweaking html), the templates are picked up by the binary on the fly and there is no need to recompile. The speed and memory usage (8.8 MB so far) are pleasing. Now I can update old apps and ship new ones.

UPDATE: With a simple update to Vapor 1.5.14, without changing any code, the site started using even less memory — 6.7–7.7 MB.

[↵] open page sajt-space-in-box.md
-rw-r--r-- 1.1K Dec 8, 2016 · B2818A9 · ~2 min

Benchmarks for Vapor 1.2.5

swift backend vapor ubuntu

About a month ago I launched benchmarks for Server side Swift frameworks. Yesterday I updated my project to the new version of Vapor: 1.2.5. Previous version I used was 1.1.11.

One of the most important updates in Vapor 1.2.x is that Vapor is now using a non-blocking server.

So today I decided to run a new benchmark for my project updated to Vapor 1.2 and results surprised me. It's not only faster than the 1.1.x version, it's now equal to Node.js results!

Vapor vs. Node.js

My server:

  • 2 GB RAM
  • 1 CPU Core
  • SSD
  • 125 MBPS Out
  • Ubuntu 16.10
  • CouchDB

Benchmark from other server was launched as:

wrk -t4 -c20 -d5m https://my_url

API just gets some data from CouchDB and returns it as JSON.

[↵] open page benchmarks-for-vapor-1-2-5.md
-rw-r--r-- 1.5K Nov 12, 2016 · A3940ED · ~2 min

Swift Backend with CouchDB: Kitura vs. Vapor vs. Node.js

swift backend vapor kitura ubuntu

I made a few test projects to implement an API for my simple app to run some benchmarks. It just makes 1 request to Database and returns JSON data.

All projects was executed on Linode VPS in London:

  • 2 GB RAM
  • 1 CPU Core
  • SSD
  • 125 MBPS Out
  • Ubuntu 16.10
  • MySQL and CouchDB with equal data (about 13k rows/documents)

Benchmarks was run on another, more powerful dedicated server in Germany using wrk:

wrk -t4 -c20 -d5m https://my_url

Results are very different from other benchmarks by Ryan Collins.

What did I try:

  • Node.js 7.0 + MySQL 5.7.16
  • Node.js 7.0 + CouchDB 2.0 (via node-couchdb)
  • Vapor 1.1.11 + CouchDB 2.0 (via HTTP)
  • Kitura 1.1.1 + CouchDB 2.0 (via Kitura-CouchDB)

Total requests

Requests per second

Average Latency

Results are very disappointing for me. Node.js was 50% faster than Swift. It looks like it's still not the right time to make backends on Swift right now, unless you don't expect high load and just want to write in Swift.

UPDATE: after about a month I ran another tests for the new version of Vapor (1.2.5) vs. Node.js and Vapor was very very fast. So now I'm very optimistic about using Swift as a backend.

[↵] open page swift-backend-with-couchdb-kitura-vs--vapor-vs-node-js.md
-rw-r--r-- 2.1K Nov 9, 2016 · 101665E · ~2 min

Vapor Framework for Swift Backend

swift vapor backend мечты о fullstack

Vapor logo

In the previous post I described my impressions of four Swift frameworks. More precisely, I wrote about three, and the fourth interested me, but I only got around to it now. In short — I am thrilled. It is wonderful.

First of all, the project has good documentation. Not perfect, but very good. With examples and learning materials. Everything in one place on the site — excellent.

First, the framework has a console tool that makes it very easy to create new projects, run existing ones, build them, deploy them to various services, and even create a Docker container. I think that is awesome, because whenever you start coding some project, even a test one, you immediately remember the various tools from the Node.js world and want to have something similar here.

Second, the set of libraries in the framework is excellent. There is an HTTP client, database wrappers, WebSocket support, templates; by default it offers a good project structure with everything organized into folders. Out of the box there is excellent support for JSON and data that can be converted both from JSON and into JSON. There is even a localization mechanism.

Third, I managed to make my own mini-client for CouchDB through plain HTTP requests, and it works. So far only for reading; I have not yet had time to check writing, but the fact that it all worked made me very happy.

Fourth, all requests are logged by default, roughly like in Express.js. So you set up routing and in the console you can see where requests are coming in, at least understanding what is happening. On top of that, the framework ships with a logging tool.

Fifth — my whole small test project compiled and ran on Linux without problems or crashes. It took a long time to compile, but it works, and that is great.

For memory usage it is worse than Perfect so far. Perfect started at 3.5 MB and grew to 5 MB. Vapor starts at 11 MB and grows to 14.9 MB. We will see what happens next; for now that is still twice less than Node.js.

For now I will probably stop at Vapor — in my opinion it is wonderful :)

[↵] open page frejmvork-vapor-dlya-bekenda-na-swift.md
-rw-r--r-- 9.2K Nov 6, 2016 · 9B2B8F3 · ~8 min

Server-Side Swift Frameworks

swift backend perfect kitura zewo vapor мечты о fullstack

A couple of months ago I came across a post about server-side Swift frameworks — a performance comparison of four Swift server frameworks against each other and against Node.js. Performance caught my attention. Judging by the results, Perfect came out on top. A month later the author posted another comparison of performance, but this time tested not on macOS, but on Linux. Perfect was in the lead again.

This weekend I decided to finally get my hands on it properly. Before that I took a quick look at the four frameworks being compared: Perfect, Kitura, Vapor and Zewo. I did not have many requirements for a framework; besides standard request routing and returning responses, I needed:

  • Templating support, so it can return not only JSON, but HTML too.
  • Support for network requests, since Foundation still has nothing ready for networking.
  • Preferably ready-made libraries for working with different databases.

Naturally, all of this needs to work under Linux.

[↵] open page frejmvork-perfect-dlya-servernogo-swift.md
-rw-r--r-- 577B Oct 28, 2016 · 7DC1233 · ~1 min

Shake effect animation for UIView

шпаргалки swift
// MARK: - UIView Extension, or NSView
extension UIView {

    /// Shake animation
    func shake() {
        let animation = CAKeyframeAnimation(keyPath: "transform.rotation")
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
        animation.duration = 1.0
        animation.values = [-Double.pi / 6, Double.pi / 6, -Double.pi / 6, Double.pi / 6, -Double.pi / 7, Double.pi / 7, -Double.pi / 8, Double.pi / 8, 0.0 ]

        layer.add(animation, forKey: "shake")
    }

}

myView.shake()

[↵] open page shake-effekt-dlya-uiview.md
-rw-r--r-- 3.2K Sep 29, 2016 · E72E8DF · ~3 min

On Migrating to Swift 3 and Swift 2.4

swift

Over the past couple of weeks, new versions of macOS, iOS, tvOS, and watchOS have been released. Along with them came a new Xcode and a new version of Swift.

When you open a project in the new Xcode, it immediately offers to convert the project to the new Swift version—either to version 2.3, which is almost unchanged as an intermediate version, or straight to the new Swift 3, which has quite a lot of changes.

Converting the project itself is not difficult, because Xcode has a built-in converter. I decided to try 2.3 first so as not to dive into the weeds of the changes. The working project converted without problems, and then dependency hell began. I use Carthage; all dependencies are compiled into a .framework that you import into your project. Once imported, you usually do not need to touch the project itself anymore, just rebuild the dependencies. In the first week after the release, many developers quickly shipped updates—a release for Swift 2.3 and a release for Swift 3. But not everyone. For example, SwiftyJSON: its developers disappeared for a while, and the framework is very popular. I had to dig around—the dependencies that had not been updated were fortunately picked up by third-party developers. They forked them, moved everything to Swift 2.3, and sent pull requests to the original repositories.

I had to spend some time replacing some dependencies with forks. And hooray, the project finally built. During the following week, the authors of all the dependencies I use had already shipped Swift 2.3 releases. With a clear conscience, I switched the dependencies back to the originals.

Naturally, it made sense to move to Swift 3 as soon as possible, because 2.3 is a temporary version and support for it will disappear in future Xcode releases. Besides, Swift 3 was promised to be, if possible, the last version that would break compatibility with previous versions.

Again, the project itself converted to Swift 3 without major issues. Not everything, but a lot. And whatever did not convert automatically, Xcode itself suggested fixes during compilation; for the most part I only had to click the mouse and let it apply them. Even though I waited until all dependencies were updated to Swift 3, I still had to sweat a bit. Incidentally, if a framework is compiled in Swift 2.3, you cannot include it in a Swift 3 project. And vice versa too. I cleared up various problems—and then a different kind of headache started. AlamoFire for Swift 3 did not just get updated, it got a major update—with renamed classes and API changes. As a result, I had to rewrite some methods by two thirds. Although in most cases I just had to swap argument order and rename things here and there. Plus, now to pass GET parameters, you have to add them to the URL string by hand; previously the parameters argument could do that, but now that data is sent in the request body as if we had filled in a form.

But in the end everything turned out fine, although the migration took time and effort. Onward, into the future.

P.S. The open-source version of Swift 3, which can run on Linux, still does not have a full implementation of the classes for working with networking. And the backend framework Perfect does not compile on Ubuntu 16.04. So Swift for the backend is postponed again for now.

[↵] open page pro-perehod-na-swift-3-i-swift-2-4.md
-rw-r--r-- 996B Sep 26, 2016 · 55D7D8F · ~1 min

An Elegant Notification.Name Extension in Swift 3

swift шпаргалки

In the new Swift 3 there is now a different initializer for NSNotification (now simply Notification; the NS prefix was dropped):

struct Config {
    static let ShouldCloseBrowserNotification = "ShouldCloseBrowserNotification"
}

let notification = Notification(
    name: Notification.Name(rawValue: Config.ShouldUpdateDialogNotification),
    object: nil,
    userInfo: nil
)
NotificationCenter.default.post(notification)

The name parameter does not look very nice now. But you can extend Notification.Name to make it look better:

extension Notification.Name {
    static let shouldCloseBrowserNotification = Notification.Name("ShouldCloseBrowserNotification")
}

let notification = Notification(
    name: .ShouldUpdateDialogNotification,
    object: nil,
    userInfo: nil
)
NotificationCenter.default.post(notification)

UIKit itself is structured in roughly the same way:

UIKit code

[↵] open page elegantnyj-extension-dlya-notification-name-v-swift-3.md
-rw-r--r-- 712B Aug 18, 2016 · 14091F5 · ~1 min

A Block (Closure) as a Class Property in Swift

swift шпаргалки

An example of using a block (closure) as a class property in Swift.

class ChatViewController: UIViewController {

    private var someClosure: (() -> Void)?
    private var anotherClosure: ((arg: Double) -> Bool)?

    func executeClosures() {
        if self.someClosure != nil {
            self.someClosure()
        }

        if self.anotherClosure != nil {
            let boolResult = self.anotherClosure(arg: 2.0)
        }
    }

    func addSelfClosure(closure: (() -> Void)!) {
        self.someClosure = closure
    }

    func printSomething() {
        self.addSelfClosure() {
            print("closure called")
        }
        self.executeClosures() // prints: closure called
    }

} 
[↵] open page blok-zamykanie--kak-svojstvo-klassa-v-swift.md
-rw-r--r-- 2.9K Aug 12, 2016 · EC7C9DE · ~2 min

Custom Badge for UITabBarController in Swift

swift шпаргалки uitabbarcontroller

It was 2016, and to change the colors of a badge inside a tab you still had to create your own UI element and add it to the tab bar manually. A working solution in Swift:

// MARK: - UITabBarController extension for badges
extension UITabBarController {

    /**
    Set badges

    - parameter badgeValues: values array
    */
    func setBadges(badgeValues: [Int]) {

        for view in self.tabBar.subviews {
            if view is CustomTabBadge {
                view.removeFromSuperview()
            }
        }

        for index in 0...badgeValues.count-1 {
            if badgeValues[index] != 0 {
                addBadge(
                    index: index,
                    value: badgeValues[index],
                    color:UIColor.yellowColor(),
                    font: UIFont.systemFontOfSize(11)
                )
            }
        }

    }

    /**
    Add badge for tab

    - parameter index: index of tab
    - parameter value: badge value
    - parameter color: badge color
    - parameter font: badge font
    */
    func addBadge(index: Int, value: Int, color: UIColor, font: UIFont) {
        let badgeView = CustomTabBadge()

        badgeView.clipsToBounds = true
        badgeView.textColor = UIColor.whiteColor()
        badgeView.textAlignment = .Center
        badgeView.font = font
        badgeView.text = String(value)
        badgeView.backgroundColor = color
        badgeView.tag = index
        tabBar.addSubview(badgeView)

        self.positionBadges()
    }

    override public func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        self.tabBar.setNeedsLayout()
        self.tabBar.layoutIfNeeded()
        self.positionBadges()
    }

    /**
    Positioning
    */
    func positionBadges() {

        var tabbarButtons = self.tabBar.subviews.filter { (view: UIView) -> Bool in
            return view.userInteractionEnabled // only UITabBarButton are userInteractionEnabled
        }

        tabbarButtons = tabbarButtons.sort({ $0.frame.origin.x < $1.frame.origin.x })

        for view in self.tabBar.subviews {
            if view is CustomTabBadge {
                let badgeView = view as! CustomTabBadge
                self.positionBadge(badgeView, items:tabbarButtons, index: badgeView.tag)
            }
        }
    }

    /**
    Position for badge

    - parameter badgeView: badge view
    - parameter items: tab bar buttons array
    - parameter index: index of tab
    */
    func positionBadge(badgeView: UIView, items: [UIView], index: Int) {

        let itemView = items[index]
        let center = itemView.center

        let xOffset: CGFloat = 12
        let yOffset: CGFloat = -14
        badgeView.frame.size = CGSizeMake(17, 17)
        badgeView.center = CGPointMake(center.x + xOffset, center.y + yOffset)
        badgeView.layer.cornerRadius = badgeView.bounds.width/2
        tabBar.bringSubviewToFront(badgeView)
    }

}

/// Custom UILabel class for badge view
class CustomTabBadge: UILabel {}
[↵] open page kastomnyj-bejdzh-dlya-uitabbarcontroller-na-swift.md
-rw-r--r-- 1.0K Aug 9, 2016 · FDC24F3 · ~1 min

Delay Function in Swift

swift шпаргалки

A very nice bit of syntactic sugar: a function for running code with a delay via Grand Central Dispatch using dispatch_after:

Update 2024. Swift 5.5+

If you need a delay inside an async function:
func someMethod() async throws {
    // sleep for 2 seconds
    try await Task.sleep(nanoseconds: NSEC_PER_SEC * 2)
}

Swift 2:

/**
Delay function using GCD. Syntax sugar.

- parameter delay: delay in seconds
- parameter closure: closure code to execute after delay
*/
func delay(delay:Double, closure:()->()) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
    dispatch_get_main_queue(), closure)
}

Swift 3:

/**
Delay function using GCD. Syntax sugar.

- parameter delay: delay in seconds
- parameter closure: closure code to execute after delay
*/
func delay(_ delay: Double, closure:()->()) {
    let when = DispatchTime.now() + delay
    DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}

Usage:

delay(0.4) {
    // code
}
[↵] open page funktsiya-zaderzhki-na-swift.md
-rw-r--r-- 705B Jun 14, 2016 · B548F4B · ~1 min

A modal UIViewController with transparency

swift шпаргалки

Cheat sheet: how to present a UIViewController over another one so that it is semi-transparent and the content underneath shows through.

In Storyboard, set the Segue Kind field to «Present Modally». For the UIViewController you are showing, set the background color to Clear Color, then create an inner background (an image or another UIView) with an alpha value, for example 0.5.

In code:

self.performSegueWithIdentifier("segueName", sender: self)

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "segueName" {
        let vc = segue.destinationViewController as! YourViewController
        vc.modalPresentationStyle = .Custom
    }
}
[↵] open page modal-nyj-uiviewcontroller-s-prozrachnost-yu.md
-rw-r--r-- 1.4K May 12, 2016 · 6FA87ED · ~1 min

Testing asynchronous code in XCTest

swift xctest тесты шпаргалки

While writing tests in the app, I ran into the fact that tests containing asynchronous code did not work. For example, if we make an asynchronous network request and then verify the result inside the callback block. The assertions simply did not run, and Xcode said the test had passed successfully even when it obviously should not have.

While googling, I found two solutions: one via semaphores from Grand Central Dispatch, the other with expectations. I liked the expectations approach more. Example test:

import XCTest

class apiClientTests: XCTestCase {
    override func setUp() {
        super.setUp()
    }

    override func tearDown() {
        super.tearDown()
    }

    /**
    SampleTest
    */
    func testSampleAsyncRequest() {
        let exp = expectationWithDescription("\(#function)\(#line)")

        APIClient.sharedInstance.someMethod { (responseObject, error) in
            XCTAssertNotNil(responseObject, "responseObject should not be nil")
            XCTAssertNil(error, "error should be nil")

            exp.fulfill()
        }

        waitForExpectationsWithTimeout(40) { (error) in
            if error != nil {
                XCTAssertTrue(false)
            }
        }
    }
}

P.S. — if you want tests to run in a specific order, remember that they are run in plain alphabetical order. So you need to name them test1Name, test2Name, and so on.

[↵] open page testirovanie-asinhronnogo-koda-v-xctest.md
-rw-r--r-- 3.2K May 12, 2016 · 46A3DE7 · ~3 min

On using Swift on the server

swift ubuntu

I started trying Swift on the server for backend work. With macOS, it is all fairly clear in terms of how to start using Swift (at least there is Xcode), but on Linux it turned out to be much less obvious.

The Swift.org website has instructions for OS X and for Ubuntu (14.04 and 15.04). I was immediately happy to see that they provide precompiled binaries. In short: download the archive, download various keys and signatures, verify the archive signature just in case, unpack the archive, and run export so the command can be executed from the console. For example:

swift --version
Swift version 2.2.1-dev (LLVM da67bff217, Clang 81d0486fb2, Swift 82adb8fc96)
Target: x86_64-unknown-linux-gnu

Start with some simple Hello World: just create a small project that prints text to the console, something like:

import Foundation

print("hello world")

Then you need to check whether it works. Run:

swift build
error: unable to invoke subcommand: /home/webserver/swift-2.2.1-SNAPSHOT-2016-04-23-a-ubuntu14.04/usr/bin/swift-build (No such file or directory)

Surprise! The release version of Swift 2.2.1 does not include swift-build. In other words, we cannot build a project with the release version. That is a bit mind-blowing. You start googling and it turns out that you need to download the dev version of Swift. And that is a pre-release version of Swift 3.0.

That version has everything, the project builds, the binary runs, and it prints text to the console. But it is still strange that the tutorial from the website does not work with the release version. Although they say it was present in previous releases.

The saddest part is that you still cannot even send network requests from open-source Swift: NSURLRequest is not implemented in Foundation, which means my idea of using CouchDB through its REST API can be postponed for now. And on GitHub there is still this line in the description of Swift's current state:


NSURLSession and related classes are not yet implemented.

You can, of course, use C libraries. For example, IBM use a CURL wrapper called CCurl. But I would prefer something out of the box, using language tools. So I will probably wait until they finally add it.

My tinkering with the Swift Express web framework showed that it is possible to build a website or REST API with it. Yesterday evening I even made a scaffold for rewriting this blog — templates are ready, routing is ready, the whole site design is rendered, only the database data remains to be wired in. And now the question is how to fetch data from the database. There are wrappers over C libraries for MySQL and MongoDB, but I still want to keep using CouchDB, since I already use it in many projects. And it has a REST API, which means the data must be fetched over network requests, which Foundation still does not provide, and I do not really want to use third-party tools because once everything is implemented, switching to built-in tools will make more sense, so I would have to rip that code out. I will wait a bit longer before rewriting my little blog in Swift :)

[↵] open page pro-ispol-zovanie-swift-na-servere.md
-rw-r--r-- 961B May 11, 2016 · 61AD73C · ~1 min

A note on Socket.IO-Client-Swift

socket.io swift шпаргалки

A small cheat sheet: there is a Swift client for socket.io. At first glance, GitHub documents how to use it pretty well. The problem is that it absolutely did not want to connect to my Node.js backend with the sample code.

The logs showed (when trying polling requests) that the client was hitting /engine.io and getting a 404 error. Studying the browser JavaScript library, which works with the same backend without any dancing with a tambourine, showed that a different path had to be specified: /socket.io. Fortunately, there is a dedicated option for that.

So in the end, this is what we get:

let socketURL = NSURL(string: "http://localhost:3000")
let socket = SocketIOClient(socketURL: socketURL!, options: [
    .ForceWebsockets(true),
    .Path("/socket.io/"),
    .ConnectParams(["token": "token"])
])

socket.on("connect") {data, ack in
    print("socket connected")
}

socket.connect() 
[↵] open page zametka-pro-socket-io-client-swift.md
-rw-r--r-- 307B Apr 22, 2016 · 4E22F08 · ~1 min

Converting a UTC date with milliseconds from String to NSDate in Swift

swift шпаргалки

To convert a date from text into NSDate from a slightly non-standard format with milliseconds:

let dateString = "2016-04-22T17:42:46.762+03:00"

let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"

let myDate = dateFormatter.dateFromString(dateString) 
[↵] open page konvertirovanie-utc-daty-s-millisekundami-iz-string-v-nsdate.md
-rw-r--r-- 810B Apr 18, 2016 · E93D4A7 · ~1 min

A log function for Swift that outputs file, method, and line

шпаргалки swift полезное

A cheat-sheet function for logging in Swift:

import Foundation

/**
 A log function that outputs the file, method, and line it was called from. 
 Example usage: DLog("hello")

 - parameter messages: text/objects to print
 - parameter fullPath: path to the calling file
 - parameter line: line number in the file
 - parameter functionName: name of the calling method/function
*/
func DLog(messages: Any..., fullPath: String = #file, line: Int = #line, functionName: String = #function) {
     let file = NSURL.fileURLWithPath(fullPath)
     for message in messages {
          print("\(file.pathComponents!.last!):\(line) -> \(functionName) \(message)")
     }
}

// Example:
DLog("message 1", "message 2")
// YourClass.swift:42 -> someMethod() message 1
// YourClass.swift:42 -> someMethod() message 2
[↵] open page log-funktsiya-dlya-swift-s-vyvodom-fajla-metoda-i-stroki.md
makoni@arm1:~/blog$ cd .. // ↵ back to all posts