HomeiOS DevelopmentDeep dive into Swift frameworks

Deep dive into Swift frameworks


Be taught the whole lot about Swift modules, libraries, packages, closed supply frameworks, command line instruments and extra.

Fundamental definitions

To start with you need to have a transparent understanding in regards to the fundamental phrases. Should you already know what’s the distinction between a module, package deal, library or framework you possibly can skip this part. Nevertheless for those who nonetheless have some combined emotions about these items, please learn forward, you received’t remorse it. 😉

Bundle

A package deal consists of Swift supply recordsdata and a manifest file.

A package deal is a set of Swift supply recordsdata. In case you are utilizing Swift Bundle Supervisor you even have to supply a manifest file so as to make an actual package deal. If you wish to study extra about this instrument, you need to test my Swift Bundle Supervisor tutorial.

Instance: that is your package deal:

Sources
    my-source-file.swift
Bundle.swift

It’s also possible to try the open sourced swift-corelibs-foundation package deal by Apple, which is used to construct the Basis framework for Swift.

Library

Library is a packaged assortment of object recordsdata that program can hyperlink towards.

So a library is a bunch of compiled code. You’ll be able to create two sorts of libraries:

From a extremely easy perspective the one distinction between them is the tactic of “integrating” aka. linking them into your mission. Earlier than I inform you extra about this course of, first we should always speak about object recordsdata.

Mach-O file format

To create applications, builders convert supply code to object recordsdata. The item recordsdata are then packaged into executable code or static libraries.

If you’re compiling the supply recordsdata you’re principally making object recordsdata, utilizing the Mach-O (MachObject) file format. These recordsdata are the core constructing blocks of your purposes, frameworks, and libraries (each dynamic and static).

Linking libraries

Linking refers back to the creation of a single executable file from a number of object recordsdata.

In different phrases:

After the compiler has created all the item recordsdata, one other program is named to bundle them into an executable program file. That program is named a linker and the method of bundling them into the executable is named linking.

Linking is simply combining all of your object recordsdata into an executable and resolving all of the externals, so the system will be capable to name all of the capabilities contained in the binary.

Static linking

The supply code of the library is actually going to be copied into the appliance’s supply. This can end in a giant executable, it’ll take extra time to load, so the binary can have a slower startup time. Oh, did I point out that if you’re making an attempt to hyperlink the identical library greater than as soon as, the method will fail due to duplicated symbols?

Deep dive into Swift frameworks

This technique has benefits as properly, for instance the executable will at all times include the right model of the library, and solely these elements will likely be copied into the principle software which can be actually used, so that you don’t should load the entire stuff, however it looks like dynamic linking goes to be higher in some instances.

Dynamic linking

Dynamic libraries will not be embedded into the supply of the binary, they’re loaded at runtime. Because of this apps might be smaller and startup time can considerably be sooner due to the light-weight binary recordsdata. As a free of charge dynamic libraries might be shared with a number of executables to allow them to have decrease reminiscence footprints. That’s why generally they’re being referred as shared libraries.

Dynamic linking

In fact if the dynamic library is just not obtainable – or it’s obtainable however their model is incompatible – your software received’t run or it’ll crash. Alternatively this may be a bonus, as a result of the writer of the dynamic library can ship fixes and your app can profit from these, with out recompilation.

Luckily system libraries like UIKit are at all times obtainable, so that you don’t have to fret an excessive amount of about this subject…

Framework

A framework is a hierarchical listing that encapsulates shared sources, corresponding to a dynamic shared library, nib recordsdata, picture recordsdata, localized strings, header recordsdata, and reference documentation in a single package deal.

So let’s make this straightforward: frameworks are static or dynamic libraries packed right into a bundle with some additional property, meta description for versioning and extra. UIKit is a framework which wants picture property to show a number of the UI parts, additionally it has a model description, by the way in which the model of UIKit is identical because the model of iOS.

Module

Swift organizes code into modules. Every module specifies a namespace and enforces entry controls on which elements of that code can be utilized outdoors of the module.

With the import key phrase you’re actually importing exterior modules into your sorce. In Swift you’re at all times utilizing frameworks as modules, however let’s return in time for some time to know why we wanted modules in any respect.

import UIKit
import my-awesome-module

Earlier than modules you needed to import framework headers instantly into your code and also you additionally needed to hyperlink manually the framework’s binary inside Xcode. The #import macro actually copy-pasted the entire resolved dependency construction into your code, and the compiler did the work on that vast supply file.

It was a fragile system, issues may go unsuitable with macro definitions, you may simply break different frameworks. That was the explanation for outlining prefixed uppercased very lengthy macro names like: NS_MYSUPERLONGMACRONAME… 😒

There was an different subject: the copy-pasting resulted in non-scalable compile occasions. With a view to clear up this, precompiled header (PCH) recordsdata had been born, however that was solely a partial resolution, as a result of they polluted the namespace (you realize for those who import UIKit in a PCH file it will get obtainable in in all places), and no-one actually maintained them.

Modules and module maps

The holy grail was already there, with the assistance of module maps (defining what sort of headers are a part of a module and what’s the binary that has the implementation) we’ve bought encapsulated modular frameworks. 🎉 They’re individually compiled as soon as, the header recordsdata are defining the interface (API), and the (routinely) linked dylib file comprises the implementation. Hurray, no must parse framework headers throughout compilation time (scalability), so native macro definitions received’t break something. Modules can include submodules (inheritance), and also you don’t should hyperlink them explicitly inside your (Xcode) mission, as a result of the .modulemap file has all the data that the construct system wants.

Finish of the story, now you realize what occurs below the hood, once you import Basis or import UIKit.

Now that you realize the logic behind the entire dynamic modular framework system, we should always begin analyzing the instruments that make this infrastructure potential.

All the time learn the person pages, aka. RTFM! Should you don’t prefer to learn that a lot, you possibly can obtain the instance mission from GitLab and open the makefiles for the essence. There will likely be 3 important classes: C, Swift and Xcode mission examples.

clang

the Clang C, C++, and Goal-C compiler

Clang is a compiler frontend for C languages (C, C++, Goal-C). In case you have ever tried to compiled C code with gcc throughout your college years, you possibly can think about that clang is kind of the identical as gcc, however these days it may well do much more.

clang -c important.c -o important.o #compiles a C supply file

LLVM: compiler backend system, which may compile and optimize the intermediate illustration (IR) code generated by clang or the Swift compiler for instance. It’s language impartial, and it may well accomplish that many issues that would match right into a e-book, however for now let’s say that LLVM is making the ultimate machine code to your executable.

swiftc

The Swift compiler, there isn’t a handbook entry for this factor, however don’t fear, simply fireplace up swiftc -h and see what can supply to you.

swiftc important.swift #compiles a Swift supply file

As you possibly can see this instrument is what truly can compile the Swift supply recordsdata into Mach-O’s or last executables. There’s a quick instance within the hooked up repository, you need to test on that for those who’d prefer to study extra in regards to the Swift compiler.

ar

The ar utility creates and maintains teams of recordsdata mixed into an archive. As soon as an archive has been created, new recordsdata might be added and present recordsdata might be extracted, deleted, or changed.

So, in a nutshell you possibly can zip Mach-O recordsdata into one file.

ar -rcs myLibrary.a *.o

With the assistance of ar you had been capable of create static library recordsdata, however these days libtool have the identical performance and much more.

ranlib

ranlib generates an index to the contents of an archive and shops it within the archive. The index lists every image outlined by a member of an archive that may be a relocatable object file.

ranlib can create an index file contained in the static lib, so issues are going to be sooner once you’re about to make use of your library.

ranlib myLibrary.a

So ranlib & ar are instruments for sustaining static libraries, often ar takes care of the indexing, and also you don’t should run ranlib anymore. Nevertheless there’s a higher choice for managing static (and dynamic) libraries that you need to study…

libtool

create libraries

With libtool you possibly can create dynamically linked libraries, or statically linked (archive) libraries. This instrument with the -static choice is meant to switch ar & ranlib.

libtool -static *.o -o myLibrary.a

These days libtool is the principle choice for increase library recordsdata, you need to undoubtedly study this instrument for those who’re into the subject. You’ll be able to test the instance mission’s Makefile for more information, or as often you possibly can learn the manuals (man libtool). 😉

ld

The ld command combines a number of object recordsdata and libraries, resolves references, and produces an ouput file. ld can produce a last linked picture (executable, dylib, or bundle).

Let’s make it easy: that is the linker instrument.

ld important.o -lSystem -LmyLibLocation -lmyLibrary -o MyApp

It could possibly hyperlink a number of recordsdata right into a single entity, so from the Mach-O’s you’ll be capable to make an executable binary. Linking is critical, as a result of the system must resolve the addresses of every technique from the linked libraries. In different phrases, the executable will be capable to run and your entire capabilities will likely be obtainable for calling. 📱

nm

show title checklist (image desk)

With nm you possibly can see what symbols are inside a file.

nm myLibrary.a
# 0000000000001000 A __mh_execute_header
#                  U _factorial
# 0000000000001f50 T _main
#                  U _printf
#                  U dyld_stub_binder

As you possibly can see from the output, some sort of reminiscence addresses are related for a few of symbols. People who have addresses are literally resolved, all of the others are coming from different libraries (they’re not resolved but). So because of this they’ll be resolved at runtime. The opposite choice is that it’s important to hyperlink them. 😅

otool

object file displaying instrument

With otool you possibly can study the contents of Mach-O recordsdata or libraries.

otool -L myLibrary.a
otool -tV myLibrary.a

For instance you possibly can checklist the linked libraries, or see the disassembled textual content contents of the file. It’s a extremely useful instrument for those who’re acquainted with the Mach-O file format, additionally good one to make use of for reverse-engineer an present software.

lipo

create or function on common recordsdata

With the assistance of the lipo instrument you possibly can create common (multi-architecture) recordsdata. Normally this instrument is used for creating common frameworks.

lipo -create -output myFramework.framework gadgets.framework simulator.framework

Think about the next state of affairs: you construct your sources each for arm7 and i386. On an actual machine you’d must ship the arm7 model, however for the iOS simulator you’ll want the i386 one. With the assistance of lipo you possibly can mix these architectures into one, and ship that framework, so the top consumer don’t have to fret about this subject anymore.

Learn on the article to see the way it’s achieved. 👇

These instruments might be invoked from the command line as properly, however they’re far more associated to Xcode than those earlier than. Let’s have a fast walk-through.

xcode-select

Manages the lively developer listing for Xcode and BSD instruments. In case you have a number of variations of Xcode in your machine this instrument can simply swap between the developer instruments supplied by the induvidual variations.

xcode-select --switch path/to/Xcode.app

xcrun

Run or find growth instruments and properties. With xcrun you possibly can principally run something you could handle from Xcode.

xcrun simctl checklist #checklist of simulators

codesign

Create and manipulate code signatures

It could possibly signal your software with the correct signature. Normally this factor failed once you had been making an attempt to signal your app earlier than automated signing was launched.

codesign -s "Your Firm, Inc." /path/to/MyApp.app
codesign -v /path/to/MyApp.app

xcodebuild

construct Xcode initiatives and workspaces

That’s it. It’ll parse the Xcode mission or workspace file and executes the suitable buid instructions based mostly on it.

xcodebuild -project Instance.xcodeproj -target Instance
xcodebuild -list
xcodebuild -showsdks

FAT frameworks

Learn how to make a closed supply common FATtened (multi-architecture) Swift framework for iOS?

So we’re right here, the entire article was made for studying the logic behind this tutorial.

To start with, I don’t wish to reinvent the wheel, as a result of there’s a fantastically written article that you need to learn. Nevertheless, I’d like to present you some extra detailed clarification and somewhat modification for the scripts.

Skinny vs. FAT frameworks

Skinny frameworks comprises compiled code for just one structure. FAT frameworks alternatively are containing “slices” for a number of architectures. Architectures are principally referred as slices, so for instance the i386 or arm7 slice.

This implies, for those who compile a framework just for i386 and x86_64 architectures, it’s going to work solely on the simulator and horribly fail on actual gadgets. So if you wish to construct a really common framework, it’s important to compile for ALL the present architectures.

Constructing a FAT framework

I’ve a excellent news for you. You simply want one little construct section script and an combination goal so as to construct a multi-architecture framework. Right here it’s, shamelessly ripped off from the supply article, with some additional adjustments… 😁

set -e
BUILD_PATH="${SRCROOT}/construct"
DEPLOYMENT_PATH="${SRCROOT}"
TARGET_NAME="Console-iOS"
FRAMEWORK_NAME="Console"
FRAMEWORK="${FRAMEWORK_NAME}.framework"
FRAMEWORK_PATH="${DEPLOYMENT_PATH}/${FRAMEWORK}"

# clear the construct folder
if [ -d "${BUILD_PATH}" ]; then
    rm -rf "${BUILD_PATH}"
fi

# construct the framework for each structure utilizing xcodebuild
xcodebuild -target "${TARGET_NAME}" -configuration Launch 
    -arch arm64 -arch armv7 -arch armv7s 
    only_active_arch=no defines_module=sure -sdk "iphoneos"

xcodebuild -target "${TARGET_NAME}" -configuration Launch 
    -arch x86_64 -arch i386 
    only_active_arch=no defines_module=sure -sdk "iphonesimulator"

# take away earlier model from the deployment path
if [ -d "${FRAMEWORK_PATH}" ]; then
    rm -rf "${FRAMEWORK_PATH}"
fi

# copy freshly constructed model to the deployment path
cp -r "${BUILD_PATH}/Launch-iphoneos/${FRAMEWORK}" "${FRAMEWORK_PATH}"

# merge all of the slices and create the fats framework
lipo -create -output "${FRAMEWORK_PATH}/${FRAMEWORK_NAME}" 
    "${BUILD_PATH}/Launch-iphoneos/${FRAMEWORK}/${FRAMEWORK_NAME}" 
    "${BUILD_PATH}/Launch-iphonesimulator/${FRAMEWORK}/${FRAMEWORK_NAME}"

# copy Swift module mappings for the simulator
cp -r "${BUILD_PATH}/Launch-iphonesimulator/${FRAMEWORK}/Modules/${FRAMEWORK_NAME}.swiftmodule/" 
    "${FRAMEWORK_PATH}/Modules/${FRAMEWORK_NAME}.swiftmodule"

# clear up the construct folder once more
if [ -d "${BUILD_PATH}" ]; then
    rm -rf "${BUILD_PATH}"
fi

You’ll be able to at all times study the created framework with the lipo instrument.

lipo -info Console.framework/Console
#Architectures within the fats file: Console.framework/Console are: x86_64 i386 armv7 armv7s arm64

Utilization

You simply should embed your model new framework into the mission that you simply’d like to make use of and set some paths. That’s it. Nearly…

Build settings

Transport to the App Retailer

There is just one subject with fats architectures. They include slices for the simulator as properly. If you wish to submit your app to the app retailer, it’s important to reduce off the simulator associated codebase from the framework. The explanation behind that is that no precise actual machine requires this chunk of code, so why submit it, proper?

APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"

# take away unused architectures from embedded frameworks
discover "$APP_PATH" -name '*.framework' -type d | whereas learn -r FRAMEWORK
do
    FRAMEWORK_EXECUTABLE_NAME=$(defaults learn "$FRAMEWORK/Information.plist" CFBundleExecutable)
    FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
    echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"

    EXTRACTED_ARCHS=()

    for ARCH in $ARCHS
    do
        echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
        lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
        EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
    achieved

    echo "Merging extracted architectures: ${ARCHS}"
    lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[@]}"
    rm "${EXTRACTED_ARCHS[@]}"

    echo "Changing authentic executable with thinned model"
    rm "$FRAMEWORK_EXECUTABLE_PATH"
    mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"

achieved

This little script will take away all of the pointless slices from the framework, so that you’ll be capable to submit your app by way of iTunesConnect, with none points. (ha-ha-ha. 😅)

It’s important to add this final script to your software’s construct phases.

If you wish to get acquainted with the instruments behind the scenes, this text will make it easier to with the fundamentals. I couldn’t discover one thing like this however I wished to dig deeper into the subject, so I made one. I hope you loved the article. 😉

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments