<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>lonelybytes</title>
    <link>https://lonelybytes.com/</link>
    <atom:link href="https://lonelybytes.com/feed.xml" rel="self" type="application/rss+xml"/>
    <description>Alex Babaev — iOS and Swift development, Ångström, Feediq, and occasional writing.</description>
    <language>en</language>
    <lastBuildDate>Mon, 02 Mar 2026 00:00:00 +0000</lastBuildDate>
    <item>
      <title>I’m free</title>
      <link>https://lonelybytes.com/blog-en/2026/3/1/im-free</link>
      <guid isPermaLink="true">https://lonelybytes.com/blog-en/2026/3/1/im-free</guid>
      <pubDate>Mon, 02 Mar 2026 00:00:00 +0000</pubDate>
      <description>I’m feeling enthusiastic about what I’m doing. Again. First time in many, many years. I feel like I’m back in 2007, when the iPhone was announced and I was preparing to develop for the new device. I felt the same way when I was first introduced to IntelliJ IDEA and its editing power. Yes, it is about coding agents.

I’m an old developer. Not that old, but I’ve been coding professionally for more t</description>
      <content:encoded><![CDATA[<p>I’m feeling enthusiastic about what I’m doing. Again. First time in many, many years. I feel like I’m back in 2007, when the iPhone was announced and I was preparing to develop for the new device. I felt the same way when I was first introduced to IntelliJ IDEA and its editing power. Yes, it is about coding agents.</p>
<p>I’m an old developer. Not that old, but I’ve been coding professionally for more than 25 years. Like, every day (almost), for at least some time, I’m writing code. I’m opinionated. I’m experienced. I’m stubborn. I’m often dumb. I’m learning constantly. I’m very lazy. All those things are true. But I’m also passionate about what I do. I love programming, and I wouldn’t stop even if all computers stopped working. I started coding on a piece of paper (I had no computer back then), and I will continue to do it if there’s no other way.</p>
<p>And coding changed a lot since the 90s. New IDEs appeared: from <a href="https://en.wikipedia.org/wiki/GW-BASIC" rel="noopener">GWBasic</a>, <a href="https://en.wikipedia.org/wiki/Turbo_Pascal" rel="noopener">Borland Pascal</a>, and <a href="https://en.wikipedia.org/wiki/Sinclair_BASIC" rel="noopener">Spectrum Basic</a> to the pinnacle of IDEs, <a href="https://en.wikipedia.org/wiki/IntelliJ_IDEA" rel="noopener">IntelliJ IDEA</a>. New languages matured and disappeared, and I’ve tried lots: <a href="https://en.wikipedia.org/wiki/Pascal_(programming_language)" rel="noopener">Pascal</a>, <a href="https://en.wikipedia.org/wiki/Java_(programming_language)" rel="noopener">Java</a>, <a href="https://en.wikipedia.org/wiki/Ruby_(programming_language)" rel="noopener">Ruby</a>, <a href="https://en.wikipedia.org/wiki/C_Sharp_(programming_language)" rel="noopener">C#</a>, <a href="https://en.wikipedia.org/wiki/C%2B%2B" rel="noopener">C++</a>, <a href="https://en.wikipedia.org/wiki/Scala_(programming_language)" rel="noopener">Scala</a>, <a href="https://en.wikipedia.org/wiki/Objective-C" rel="noopener">Objective-C</a>, <a href="https://en.wikipedia.org/wiki/Swift_(programming_language)" rel="noopener">Swift</a>, <a href="https://en.wikipedia.org/wiki/Kotlin" rel="noopener">Kotlin</a>, <a href="https://en.wikipedia.org/wiki/JavaScript" rel="noopener">JavaScript</a>, and many more. Frameworks and paradigms change all the time. I love that. And of course, I want to create things. It is incredible when an abstract idea turns into something palpable (even usable sometimes). I think that this is the best thing in programming: when you have an ephemeral thought, then you work hard, and magic happens, an app appears. Or a framework, a library, whatever.</p>
<p>I’m lazy, but I’m passionate. I started with the smallest apps ever, like a <a href="https://en.wikipedia.org/wiki/Sokoban" rel="noopener">Sokoban</a> game. But I constantly moved to bigger and bigger projects. Now I’m building quite big stuff, like <a href="https://domika.app" rel="noopener">Domika</a>, or <a href="https://itraceapp.com/en/" rel="noopener">iTrace</a> apps. That is great. But I want to go bigger, and I want to do that myself. Sure, I can delegate, but why should I delegate what I love?</p>
<p>That is not easy to do. First, it is hard to create something beyond some size of “big”. Physically hard. Second, when you’re building huge stuff, you are drowning in it. And because of that, you have no time to make something “for fun”, some small and useful projects. One can say that I’m not scaling well enough. Yup, something like that.</p>
<p>Looks like it’s in the past. History is split into “before 2026” and now. I feel like I was unable to move quickly enough before. Like my hands were tied. Now I’m free. I have grown extra hands even. I can quickly prototype, create things. I can simultaneously work on several parts of a project, or several projects at once. I even have time to create useful utility stuff, which I gave up on doing long ago (because I was “busy doing other, real stuff” ‾_(ツ)_/‾). And for some strange reason, it does not feel like I’m delegating. I’m doing it myself.</p>
<p>All this stuff is so easy now. For example, these are things that I did last week (besides my daily job):</p>
<ul>
<li>created a helper app for my colleague that uses our system infrastructure and presents some data in a human-readable way, allowing him to debug and test hypotheses about it.</li>
<li>created several scripts that help me to release new versions of apps and check that my code is more consistent and accurate</li>
<li>restored an old (like, really old, 15-year-old) project. It was not working. It used APIs that are long gone. It had more than a thousand problems, according to Xcode. And I managed to update it to a fully working state in several hours, convert it to another API, and clean up all warnings (and I do mean it, every single one of them). I could’ve modernized it from Objective-C to Swift too, but at this point I don’t care, Objective-C is perfectly fine for it to work.</li>
<li>and now I have enough free time to write this text. In English (not my native language), it is kinda hard for me to do, I’m not used to writing texts in English, especially something this long.</li>
</ul>
<p>Before coding agents existed, all this would be unrealistic. Not impossible, as each task is totally doable, but it would’ve taken days. Now it takes hours. And when LLMs <a href="https://openai.com/index/introducing-gpt-5-3-codex-spark/" rel="noopener">become faster</a>, each task will take a fraction of that. Imagine the power that this unleashes. Mind-blowing.</p>
<p>Last year I was worried a lot that AI would transform programming into something hideous, something I would be repelled by. But this is the opposite of that. I feel better than ever. Programming is definitely transforming, changing into something bigger and better. And it is good. It is great. Finally, tools caught up with my mind.</p>
<p>I’m free. Again.</p>]]></content:encoded>
    </item>
    <item>
      <title>Codable with options</title>
      <link>https://lonelybytes.com/blog-en/2023/9/23/codable-with-options</link>
      <guid isPermaLink="true">https://lonelybytes.com/blog-en/2023/9/23/codable-with-options</guid>
      <pubDate>Sat, 23 Sep 2023 00:00:00 +0000</pubDate>
      <description>Let’s talk about Codable. This is a quite nice solution to encoding and parsing JSON, that is used everywhere in Swift. It is quite simple, but sometimes you need a little more than just “parse this easy thing”. I recently bumped into something like it and thought that the solution could be helpful for others.

How exactly did I meet this? I reverse engineered KEF API, to be able to control the sp</description>
      <content:encoded><![CDATA[<p>Let’s talk about <code>Codable</code>. This is a quite nice solution to encoding and parsing JSON, that is used everywhere in Swift. It is quite simple, but sometimes you need a little more than just “parse this easy thing”. I recently bumped into something like it and thought that the solution could be helpful for others.</p>
<p>How exactly did I meet this? I reverse engineered KEF API, to be able to control the speakers from the Stream Deck +. This project is quite successful, but it’s a story for another time. While investigating API I found out this piece of JSON (this was part of the current volume request):</p>
<pre><code class="language-swift">&quot;value&quot;: {
  &quot;type&quot;: &quot;i32_&quot;,
  &quot;i32_&quot;: 40
}</code></pre>
<p>After some more tinkering I found out that there are several types: standard <code>string_</code>, <code>bool_</code>, and some custom ones, like <code>kefPhysicalSource</code>.</p>
<p>This looks a lot like an enum with associated value, or some kind of union-like structure. Unfortunately, if I try to encode enum with associated values in Swift, I get [totally another structure]. This means that we need to create custom coding.</p>
<p>Let’s figure out the structure first. It contains one constant property: <code>type</code>, that defines which property name to use for the value, and its type. For <code>i32_</code> it will be an integer value, a boolean for <code>bool_</code> and string for the <code>string_</code>. Custom values like <code>kefPhysicalSource</code> can be encoded in some different way. Also we will need to create <code>CodingKeys</code> enum with all the options.</p>
<p>In theory this is an easy code to write. For decoding, we just parse <code>type</code> and then create a <code>switch</code> based on its value. Every time we need to parse another type, we add a <code>case</code> to the <code>switch</code>.</p>
<pre><code class="language-swift">public struct RawValue: Codable {
    public var value: Any // Let's skip this Any for a while

    enum CodingKeys: String, CodingKey {
        case type = &quot;type&quot;
        case int32 = &quot;i32_&quot;
        case bool = &quot;bool_&quot;
        // ... other cases
    }

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let type = try container.decode(String.self, forKey: .type)
        switch type {
            case &quot;i32_&quot;:
                value = try container.decode(Int32.self, forKey: .type)
            case &quot;bool_&quot;:
                value = try container.decode(Int32.self, forKey: .type)
            // ... other cases
        }
    }

    public func encode(to encoder: Encoder) throws {
        // Here the encoding will be :)
    }
}</code></pre>
<p>We will also need to find out a way of encoding the value correctly. For example, we can check the type of the <code>value</code>, and choose the name of the property based on it.</p>
<pre><code class="language-swift">var container = encoder.container(keyedBy: CodingKeys.self)
switch value {
    case let value as? Int32:
        try container.encode(&quot;i32_&quot;, forKey: .type)
        try container.encode(value, forKey: .int32)
    // similar code for every type
}</code></pre>
<p>This is a direct solution, and it is not really expandable. The code will be changing every time we need to parse a new type, that will result in more convoluted code, extra bugs and problems. As the code for all types is similar, it will be copy-pasted, that will lead to even more errors. Can we use Swift features to simplify this solution?</p>
<h3 id="using-swift">Using Swift</h3>
<p>Let’s think. First of all, we would like to limit the types that we can use with the <code>RawValue</code>. For example, we would like to allow <code>String</code>, <code>Int32</code>, <code>Bool</code>, custom <code>PhysicalSource</code>, but not <code>UIView</code> or <code>UInt64</code>. This can be made by using the marker protocol (I’ll skip the <code>PhysicalSource</code> for now, we’ll return to it later):</p>
<pre><code class="language-swift">public protocol RawValueType {
}

extension String: RawValueType {
}

extension Int32: RawValueType {
}

extension Bool: RawValueType {
}</code></pre>
<p>Now we can constrain <code>RawValue.value</code> to this protocol which will do the trick:</p>
<pre><code class="language-swift">public struct RawValue&lt;Type: RawValueType&gt;: Codable {
    public var value: Type?

    // Coding Keys
    // Decoding part
    // Encoding part
}</code></pre>
<p>Now we can’t create a <code>RawValue</code> with a non-parsable type.</p>
<p>Next task is to put JSON property names to a place, where we can use them for everything. The ideal place will be inside already created extensions:</p>
<pre><code class="language-swift">public protocol RawValueType {
    static var encodingType: String { get }
}

extension String: RawValueType {
    public static let encodingType: String = &quot;string_&quot;
}

extension Int32: RawValueType {
    public static let encodingType: String = &quot;i32_&quot;
}

extension Bool: RawValueType {
    public static let encodingType: String = &quot;bool_&quot;
}</code></pre>
<p>Next task is to deal with the <code>CodingKeys</code>. Usually it contains cases with JSON property names, but we need to use different names for different types. So ideally we’d like to use something like this:</p>
<pre><code class="language-swift">enum CodingKeys: CodingKey {
    case type
    case value(type: String)
}</code></pre>
<p>Looks great, but now we need to implement the requirements for the <code>CodingKey</code> protocol. Usually we do this by providing <code>rawValues</code> (<code>String</code> or <code>Int</code>), but in our case we have to do it manually:</p>
<pre><code class="language-swift">// We don't need these two, because we are using strings for the keys
init?(intValue: Int) { nil }
var intValue: Int? { nil }

init?(stringValue: String) {
    self = stringValue == &quot;type&quot; ? .type : .value(type: stringValue)
}

var stringValue: String {
    switch self {
        case .type: return &quot;type&quot;
        case .value(let type): return type
    }
}</code></pre>
<p>Now our <code>CodingKeys</code> will support custom types, and we will not need to update it ever again.</p>
<p>Let’s try to write the encoder now:</p>
<pre><code class="language-swift">public struct RawValue&lt;Type: RawValueType&gt;: Codable {
    public var value: Type?

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(Type.encodingType, forKey: .type)
        let valueKey = CodingKeys.value(type: Type.encodingType)
        try container.encode(value, forKey: valueKey)
    }
}</code></pre>
<p>Looks awesome, but it will not work for now, because the type of our value is <code>RawValueType</code>, that is not <code>Encodable</code>. Let’s make it comply, it only requires the addition of the conformance itself, that’s all.</p>
<pre><code class="language-swift">public protocol RawValueType: Codable { ... }</code></pre>
<p>OK, encoding works now, we need to think about the decoding:</p>
<pre><code class="language-swift">public struct RawValue&lt;Type: RawValueType&gt;: Codable {
    public var value: Type?

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let decodedType = try container.decode(String.self, forKey: .type)
        guard decodedType == Type.encodingType else {
            let message = &quot;\(decodedType) != \(Type.encodingType) :(&quot;
            throw DecodingError
                .dataCorruptedError(in: container, debugDescription: message)
        }

        let valueKey = CodingKeys.value(type: Type.encodingType)
        value = try container.decode(Type?.self, forKey: valueKey)
    }

    public func encode(to encoder: Encoder) throws { ... }
}</code></pre>
<p>This code will never change and adding a new type is easy, we only need to make it implement <code>RawValueType</code> protocol.</p>
<p>Wait, we’ve forgotten the <code>PhysicalSource</code>. It is different because it is custom, and may not implement <code>Codable</code> out of the box, in which case we will need to implement it ourselves.</p>
<pre><code class="language-swift">extension PhysicalSource: RawValueType {
    public static let encodingType: String = &quot;kefPhysicalSource&quot;

    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let string = try container.decode(String.self)
        switch string {
            case &quot;usb&quot;: self = .usb
            case &quot;standby&quot;: self = .standby
            default: self = .unsupported
        }
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
            case .usb: try container.encode(&quot;usb&quot;)
            case .standby: try container.encode(&quot;standby&quot;)
            case .unsupported:
                throw EncodingError.invalidValue(self, .init(codingPath: [], debugDescription: &quot;Can't encode unknown source&quot;))
        }
    }
}</code></pre>
<h3 id="result">Result</h3>
<p>In this article we went from the direct approach, that is quite unsupportable to the nice solution that uses Swift features, will be statically checked on compilation, and will not require any maintenance. I’d say that this is a success. Did I miss something? ‾*(ツ)*/‾</p>
<p>Full code can be found here:</p>
<ul>
<li>Types: <a href="https://github.com/bealex/KEFStreamDeckPlugin/blob/main/Sources/Models/RawValue.Types.swift]" rel="noopener">[https://github.com/bealex/KEFStreamDeckPlugin/blob/main/Sources/Models/RawValue.Types.swift]</a></li>
<li>RawValue Codable: <a href="https://github.com/bealex/KEFStreamDeckPlugin/blob/main/Sources/Models/RawValue.swift]" rel="noopener">[https://github.com/bealex/KEFStreamDeckPlugin/blob/main/Sources/Models/RawValue.swift]</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <title>Black Screen on Launch in Scene-Based iOS App in Xcode 14.3</title>
      <link>https://lonelybytes.com/blog-en/2023/3/27/black-screen-on-ios-app-launch</link>
      <guid isPermaLink="true">https://lonelybytes.com/blog-en/2023/3/27/black-screen-on-ios-app-launch</guid>
      <pubDate>Mon, 27 Mar 2023 00:00:00 +0000</pubDate>
      <description>Everything was OK in Xcode 14.2, but when I tried to launch one of my projects from Xcode 14.3 (still the RC, but nevertheless), I got black screen. Some logs told me that AppDelegate was initialized, but no methods related to SceneDelegate were called. Spent couple of hours to figure it out.

Long story short, there is a setting in Build Settings, that generates Info.plist for your app (GENERATE_</description>
      <content:encoded><![CDATA[<p>Everything was OK in Xcode 14.2, but when I tried to launch one of my projects from Xcode 14.3 (still the RC, but nevertheless), I got black screen. Some logs told me that <code>AppDelegate</code> was initialized, but no methods related to <code>SceneDelegate</code> were called. Spent couple of hours to figure it out.</p>
<p>Long story short, there is a setting in Build Settings, that generates <code>Info.plist</code> for your app (<code>GENERATE_INFOPLIST_FILE</code>) and another one, that generates Scene Manifest (<code>INFOPLIST_KEY_UIApplicationSceneManifest_Generation</code>). FIrst one I knew and it was already disabled. Second one was a surprise. Turned it off (it did generate empty Scene Manifest and could not load any Scenes because of that) and everything worked again!</p>]]></content:encoded>
    </item>
    <item>
      <title>Ångström Style System</title>
      <link>https://lonelybytes.com/blog-en/2014/3/23/styling-an-ios-application-dplstyler</link>
      <guid isPermaLink="true">https://lonelybytes.com/blog-en/2014/3/23/styling-an-ios-application-dplstyler</guid>
      <pubDate>Wed, 09 Apr 2014 00:00:00 +0000</pubDate>
      <description>Building an app requires iteration. Photoshop is a good place to start designing, AppCode is a good place to start developing, but when the first prototype is ready, design and development merge: most changes require coding. When the designer wants to adjust colors and fonts, refine interactions, he asks the developer to do it. This slows down the process and makes experimenting prohibitively cost</description>
      <content:encoded><![CDATA[<p>Building an app requires iteration. Photoshop is a good place to start designing, AppCode is a good place to start developing, but when the first prototype is ready, design and development merge: most changes require coding. When the designer wants to adjust colors and fonts, refine interactions, he asks the developer to do it. This slows down the process and makes experimenting prohibitively costly.</p>
<p>When Ilya and I started making <a href="https://itunes.apple.com/app/id783839219?mt=8" rel="noopener">Ångström</a>, we decided to create a flexible style engine, so that tinkering with the design would be easy for both of us.</p>
<h3 id="design-considerations">Design considerations</h3>
<p>The stylesheets must be stored separately from the code, be easy to read, write and parse. That’s why we use JSON, not Plist or CSS and keep them in a Dropbox.</p>
<p>The styles must reload on demand in the running app. No recompiling, no reinstalling, no restarting. That’s why we have Shake to Refresh.</p>
<p>The app must open fast no matter how long the stylesheet is. Ångström has ended up having hundreds of style rules, bigger apps will require thousands. That’s why we compile styles into binary.</p>
<p>The code related to styles should be easy to maintain. That’s why we do not address the style variables by string literals, i.e. <code>[styler boolForKey:@&quot;isTopBarHidden&quot;]</code>. A typo would end up being a debugging nightmare. Instead, we create an object with the corresponding fields, <code>style.isTopBarHidden</code>, and let the compiler do its job looking for errors.</p>
<h3 id="architecture">Architecture</h3>
<p>Ångström Style System has three objects:</p>
<ul>
<li><em>Styler</em> loads and stores stylesheets, sends notifications if style changes.</li>
<li><em>Style Objects</em> are created by the Styler from the stylesheets and contain typed style values.</li>
<li><em>Style Listeners</em> receive and process notifications on style changes.</li>
</ul>
<p>Styler is able to generate Style Object classes automatically from JSON. After that it can:</p>
<ul>
<li>Use <a href="http://nshipster.com/nscoding/" rel="noopener">NSArchiver</a> to save and restore styles in the binary form (for startup speed)</li>
<li>Get the values from this class the fastest way possible, simply by accessing its properties (for general application speed and convenience).</li>
</ul>
<p>For example, style system will transform this JSON:</p>
<pre><code>&quot;cursor&quot;: {
    &quot;showTime&quot;: 0.2,
    &quot;hideTime&quot;: 0.2,

    &quot;color&quot;: &quot;@colors.cursor.color&quot;,

    &quot;period12&quot;: 0.4,
    &quot;timingType12&quot;: &quot;linear&quot;,
}</code></pre>
<p>into this class:</p>
<pre><code>@interface AGRCursorStyle : ASStyleObject
    @property (…) CGFloat showTime;
    @property (…) CGFloat hideTime;
    @property (…) UIColor *color;
    @property (…) CGFloat period12;
    @property (…) AGRConfigAnimationType timingType12;
@end</code></pre>
<p><code>ASStyleObject</code> is the base class for all Style Objects.</p>
<h3 id="workflow">Workflow</h3>
<p>Before using the Styler, we need to parse JSON with the styles definitions:</p>
<pre><code>ASStyler *styler = [ASStyler sharedInstance];
[styler addStylesFromURL:@&quot;styles.json&quot;
   toClass:[AGRStyle class]
   pathForSimulatorGeneratedCache:@&quot;SOME_PATH&quot;];</code></pre>
<p>ÅSS classes have prefix “AS”. Example classes are prefixed with “AGR” for “Ångström”.</p>
<p>Here I use the <code>AGRStyle</code> class as the root class for all my styles. This is the main Style Object. The last parameter is for automatic saving of the binary cache (serialized <code>AGRStyle</code> instance that is used to speed up the application startup). It is saved during Simulator launch and allows me to be sure that this cache is up to date.</p>
<p>Of course this cache must be updated right after style was changed. But this requires IDE plugin.</p>
<p>You can get the style value like this:</p>
<pre><code>ASStyler *styler = [ASStyler sharedInstance];
AGRCursorStyle *style =
    ((AGSStyle *) styler.styleObject).cursor</code></pre>
<p>This variant allows to get the value and forget about it. A good choice If it is needed just once.</p>
<p>Also you can get the same style another way:</p>
<pre><code>AGRCursorStyle *style = [[AGRCursorStyle alloc]
   initWithStyleReloadedCallback:
        ^{
             [self styleUpdated];
         }];</code></pre>
<p>This choice allows to create a callback, that will be called when the style is updated. It’s a good place to send some a message like <code>[self setNeedsDisplay]</code>; or something that will restyle your view.</p>
<p>After that you can use the style object as a usual Objective-C object.</p>
<p>How can you create this class? When the Style System runs in the Simulator, it can generate all the classes from JSON structure for you and write a <code>ProjectStyles.h/m</code> files with them. Autogeneration can be done with this line of code:</p>
<pre><code>[styler generateStyleClassesForClassPrefix:@&quot;AGR&quot;
        savePath:@&quot;[PATH_TO_CODE]/Styles/&quot;
        needEnumImport:YES];</code></pre>
<p>It will generate <code>AGR[CapitalizedStyleName]Style</code> classes for every style rule in the JSON file. For example, a style rule “editor” will generate a class <code>AGREditorStyle</code>, and if the “editor” style rule contains “toolbar” subrule, it will become <code>AGREditorToolbarStyle</code>. Main class will be <code>AGRStyle</code>.</p>
<p>Ideally, the class generation has to happen in the IDE on the fly during JSON editing, but it requires an IDE plugin and some more coding time. I hope to do this in the future.</p>
<h3 id="stylesheet-format">Stylesheet format</h3>
<p>Stylesheets are hierarchical. Any style can be referenced via all it’s parent styles like this: <code>superstyle.parentstyle.style</code>.</p>
<p>Styler supports references. If a value looks like “@another.name”, then it is replaced with the value of “another.name” style.</p>
<p>Also there is include support. That allows creating large and detailed file with all the styles and smaller, simplier files for remote editing. Here is the example:</p>
<pre><code>&quot;@include.fonts&quot;: {
    &quot;inApp&quot;: &quot;fontStyles.json&quot;,
    &quot;remote&quot;: &quot;http://[SERVER]/fontStyles.json&quot;
},</code></pre>
<p>Includes have optional remote part that will load file from the remote server. Local part is for production, remote for development.</p>
<p>Style name suffixes define value types:</p>
<ul>
<li>color for <em>UIColor,</em></li>
<li>image for <em>UIImage,</em></li>
<li>point, origin, location, position, center for <em>CGPoint,</em></li>
<li>size or dimensions for <em>CGSize,</em></li>
<li>rect, frame, bounds for <em>CGRect,</em></li>
<li>margin(s), padding(s), border for <em>UIEdgeInsets,</em></li>
<li>font for <em>UIFont,</em></li>
<li>textattributes for <em>NSAttributedString</em> attributes (in the end it is a simple <em>NSDictionary</em> but with specific keys).</li>
</ul>
<p>For example:</p>
<pre><code>&quot;margins&quot;: [23, 15, 10, 15]
&quot;separatorColor&quot;: &quot;@colors.about.separatorColor&quot;
&quot;appBackgroundColor&quot;: &quot;#0f0d0a&quot;
&quot;listTapColor&quot;: &quot;@colors.activeColor&quot;,</code></pre>
<p>and so on.</p>
<p>Fonts and TextAttributes are dictionaries with specifically named parameters, points/sizes/rects/margins are simple arrays. Here is a font example:</p>
<pre><code>&quot;font&quot;: {
    &quot;name&quot;: &quot;HelveticaNeue&quot;,
    &quot;size&quot;: 13
}</code></pre>
<p>And this is a definition of a dictionary for <code>NSAttributedString</code>:</p>
<pre><code>&quot;normalTextAttributes&quot;: {
    &quot;font&quot;: {
        &quot;name&quot;: &quot;HelveticaNeue&quot;,
        &quot;size&quot;: 18
    },
    &quot;lineBreakMode&quot;: &quot;NSLineBreakByTruncatingTail&quot;,
    &quot;color&quot;: &quot;#990202&quot;
}</code></pre>
<p>You can define other <code>NSAttributedString</code> attributes too.</p>
<p>Style also supports “functions”. Right now there are only two of them:</p>
<pre><code>~color.alpha(COLOR, ALPHA)
~color.mix(COLOR1, COLOR2, PART)</code></pre>
<p>First one adds (or replaces) alpha channel to the color, second one takes <code>PART</code> from <code>COLOR1, (1 - PART)</code> from <code>COLOR2</code> and adds them to get a new color. Something like this:</p>
<pre><code>RESULT = COLOR1*PART + COLOR2*(1 - PART)</code></pre>
<h3 id="conclusion">Conclusion</h3>
<p>I am already using ÅSS in other projects and it helps a lot. If you have any questions or suggestions, drop me a line: <a href="mailto:alex@lonelybytes.com">alex@lonelybytes.com</a>.</p>
<p><a href="http://www.theverge.com/2013/6/10/4412350/apple-new-mac-pro-wwdc-2013" rel="noopener">Can’t innovate anymore, my ÅSS</a>! Sorry, could not help :-)</p>]]></content:encoded>
    </item>
  </channel>
</rss>
