• In this paper, starting from: ShannonChenCHN/ASwiftTour
  • Source address: ShannonChenCHN/ASwiftTour

Keywords: modularization/componentalization, OBJC-Swift mixed programming, Swift static library, ABI Stability, Module Stability, LLVM Module, Umbrella Header

directory

  • Basic preparation
    • Mix within an App Target
    • Mix in a Framework Target
  • Hit the pit
    • Project background
    • Integration of static library subprojects
    • Static link problem
    • Dynamic linking problem
    • ABI Stability andAlways Embed Swift Standard Libraryoptions
    • When modularization/componentization projects encounter Swift static libraries
      • The ObjC module calls the Swift module
      • The Swift module calls the Swift module
      • Module Stability
      • The Swift module calls the ObjC module
      • LLVM Module and Umbrella Header
    • Debug the problem
  • conclusion

First, basic preparation

There are a few questions we can’t get around before we start practicing Swift-objc mix. For example:

  • Swift and ObjC mix, how do we get started? Is there any relevant introduction in the official documentation?
  • How can Swift and ObjC be mixed in a modular/componentized project?
  • The industry is already working on Swift-ObjC coprogramming. What are they doing?
  • Where do we stand, and what considerations do we need to take into account the experience we have? What should we do?
  • What would be the impact if Swift were introduced into an existing ObjC project? Where are the restrictions?
  • .

There is a detailed description of Language Interoperability in Apple’s official documentation, which describes Interoperability from the point of view of migrating from ObjC to Swift, and summarizes this with three points:

  • How do I adjust the EXISTING ObjC and C code apis in the project to provide for Swift calls, such as adding nullability related macros and keywords, adding Swift API aliases, and so on
  • Conversion relationship between Cocoa Framework and Swift for the various base data types
  • How do I call ObjC code in Swift code, and how do I call Swift code in ObjC code

Here we focus on how the Swift code and ObjC code call each other.

1. Mix within an App Target

If it’s inside an App Target, when we create a new Swift file in our ObjC project or when we create an ObjC file in our Swift project, Xcode will automatically create a new Objective-C Bridging header file for you (which we can also create manually). In this file, we can import the ObjC header files that we need to expose to Swift code calls, So we can call ObjC’s code from Swift.

Figure 1 Creation of objective-c Bridging header files

Figure 2 shows the code for calling ObjC in Swift

If we wanted to call Swift in ObjC code, we would just say “ProductModuleName- swift.h “, because at compile time, The compiler will automatically generate a ProductModuleName- swift.h header for the Swift code in the project (which is the build product and can be seen in the build directory) and expose it to ObjC for use.

Figure 3 code for calling Swift in ObjC

2. Mix in a Framework Target

In addition to mixing within an App Target, there is another situation where we want to write a Library or Framework for someone else, and if we have ObjC and Swift mixed, The Objective-C bridging header approach doesn’t work anymore, so if we use this header file, Xcode will warn us when we precompile.

To create an umbrella header, set the parameters of Swift’s Build Settings to YES and create an umbrella header. The ObjC header file that needs to be exposed to the (internal) Swift call is then imported into this umbrella header (LLVM Module and umbrella Header are two new concepts, more on that later).

If you want to call Swift in ObjC, you also need to set the Build Settings parameter to YES. Then in reference to Swift code ObjC file import compiler to generate the header file # import < > ProductName/ProductModuleName – Swift. H.

reference

  • Developer.apple.com/documentati…

Step on the pit tour

1. Project background

-------------------------------------------------- Hotel | HotelOrder | ... Business layer -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- HotelFoundation | HotelModel |... Business base layer -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- Network | Foundation | MapKit | RNKit |... Infrastructure layer -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --Copy the code

FIG. 4 Schematic diagram of iOS client architecture of the author’s company

At present, the overall architecture of the project of the author’s company adopts modular design, and the whole project is completely realized by ObjC/C. In actual development, each module can be used in the form of source code or.A +.h + resource bundle. In short, it can be relied on source code. It can also be a static library dependency. So can we use the Swift static library directly in our project?

FIG. 5 Schematic diagram of project structure (simplified model)

As we all know, Apple has supported the use of Swift static libraries since Xcode 9, so our existing project architecture does not need to be adjusted, and Swift code can be introduced in the form of static libraries.

2. Integration of static library sub-projects

The first step is to create a Swift static library project and then integrate it as a sub-project into the ObjC main project.

The general steps are as follows:

  • Create Swift static library project (here we give it a name, calledSwiftLibAThe main project is calledMainProject)
  • Integrate Swift static library project in main project
    • Add subproject: drag the XcodeProj file of the Swift static library project to the main project
    • Add Build dependencies: in the Build Phases paneDependenciesAdd the static library target as a build dependency
    • Add the static library to link to: in the Build Phases paneLink Binary With LibrariesLink to the Swift static library
    • exportxxx-SwiftHeader file: in the Swift static library projectRun Script PhaseAdd the script to be generated by the compilerSwiftLibA-SwiftCopy the header files to the build directory (see Figure 6)
  • Call the Swift API in ObjC code
    • Add to Swift code@objc,publicKey words such as
    • Add in ObjC code#import <SwiftLibA/SwiftLibA-Swift.h>(SwiftLibA here is the name of the newly added static library)

Figure 6. Integration of Swift static library project in main project

Figure 7 copyxxx-SwiftHeader files to the build directory

Sample code:

@objcMembers
public class SwiftLibA: NSObject {
    public func sayHello(a) {
        print("Hello, this is Swift world!")}}Copy the code
@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [[SwiftLibA new] sayHello];
}

@end
Copy the code

Question:

1. Why set Dependencies?

Set Dependencies to tell Xcode Build System which other targets to compile before compiling the main project.

2. Why is Link Binary With Libraries required?

The Link Binary With Libraries setup allows you to specify which static Libraries you want to Link to.

3. Why do I need to copy the xxx-swift header to the build directory?

Because the header files automatically generated at compile time are in DerivedSources, the parent of each subproject in the Intermediates directory, Like on my computer /Users/ShannonChen/Library/Developer/Xcode/DerivedData/MainProject-aptbbpsumoitdlhbzjckyglkspoi/Build/Intermediates.noin Dex/SwiftLibA. Build/Debug – iphonesimulator/SwiftLibA. Build/DerivedSources SwiftLibA – Swift. H, The main project will go to the Products directory in the Build directory to find the header file. It’s on my computer /Users/ShannonChen/Library/Developer/Xcode/DerivedData/MainProject-aptbbpsumoitdlhbzjckyglkspoi/Build/Products/Debug-iph Onesimulator /include, so the main project or other subprojects will not find this header at compile time.

Therefore, we need to copy the xxx-swift header file to the build directory. The script is as follows:

#Copy the xxx-swift header generated by the compiler into the include directory under the build directory
include_dir=${BUILT_PRODUCTS_DIR}/include/${PRODUCT_MODULE_NAME}/
mkdir -p ${include_dir}
cp ${DERIVED_SOURCES_DIR}/*-Swift.h ${include_dir}
Copy the code

Reference:

  • Paul-samuels.com/blog/2018/0…

3. Static link problems

After integrating the Swift static library, we built it again and found that it still reported errors when linking.

Figure 8 static link error

According to the error message, swiftFoundation dynamic libraries cannot be found. This is because our main project is a pure ObjC project, so we need to tell Xcode build system the path of these Swift dynamic libraries.

Go to Library Search Paths under Build Settings TAB and add $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME), $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME) where Swift 5.0’s dynamic library resides.

Both directories are available on our computers:

  • /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphoneos
  • / Applications/Xcode. App/Contents/Developer/Toolchains/XcodeDefault xctoolchain/usr/lib/swift - 5.0 / iphoneos

Figure 9 Swift standard library

Reference:

  • stackoverflow.com/a/53101587
  • stackoverflow.com/a/57126566

4. Dynamic link problem

The static link issue has been resolved. Press ⌘+R and the simulator will crash when ⌘ starts. Dyld: Library not loaded: @rpath/libswiftCore.dylib. This is because the Swift dynamic Library failed to load when the program started.

Figure 10 program startup crash

To solve this problem, we need to set two places (both of which need to be set as long as your project iOS Deployment Target is below 12.2) :

  • For iOS 12.2 and later, you need to install theBuild SettingsUnder the TABRunpath Search PathAdd to the front of the/usr/lib/swift.
  • For operating systems prior to iOS 12.2, you need to change theBuild SettingsUnder the TABAlways Embed Swift Standard LibrariesSet toYES.

Why do we have different Settings for pre-ios 12.2 and post-ios 12.2? Does setting the Always Embed Swift Standard Libraries to YES mean that the Swift Standard library will be entered every time you pack?

Reference:

  • stackoverflow.com/a/55392717

  • stackoverflow.com/a/26949219

5. Stability and ABIAlways Embed Swift Standard Libraryoptions

The biggest news for iOS developers in 2019 is that the Swift ABI is finally stable. What does ABI Stability mean? ABI Stability refers to binary interface Stability. Apps that are built using Swift 5.0 or higher (Xcode 10.2 for Swift 5.0) will run as long as they are compatible. You can run on any Swift 5.0 or later Swift Runtime. So instead of having to bring a Swift Runtime and Standard Library with you every time you open a new app, Swift Runtime and Standard Library are built into iOS and macOS.

Figure 11 In this example, an app built on Swift 5.0 can run directly on a system with built-in Swift 5 or Swift 5.1, or even Swift 6 standard libraries

However, if you are using a compiler prior to Swift 5.0, you will still pack a Swift Runtime and Standard Library.

In addition, for apps built with Swift 5.0 or higher, Apple will create different download packages depending on the iOS system when releasing the app. For iOS 12.2 and above, because Swift 5 runtime and Standard Library are built into the system, the Swift libraries embedded in the app are no longer required and will be removed from the App Bundle. However, for iOS 12.2 and below, the Swift 5 Runtime and Standard Library are not built into the system, so you still need to pack them with you.

Now that you understand what ABI Stability is, it’s easy to understand the two Settings we made earlier in Build Settings.

When the app starts/runs, it will first look for Swift Runtime in the app bundle. If it does not find Swift Runtime, the dynamic linker dyld will look for dylib in the RunPath path (this runpath is a system directory path). So we added Runpath Search Path: /usr/lib/swift for iOS 12.2 and later, and Always Embed Swift Standard Library for pre-ios 12.2.

Figure 12 Adding Runpath Search Path

Always Embed Swift Standard Library Used to be called Embedded Content Contains Swift Code, literally “Always Embed Swift Standard Library”, But it really just tells build System what to do, and does not mean that the app downloaded on the user’s phone will be like this, because App Stochastic will automatically determine if the Swift standard library in the App bundle will be deleted when the app is launched, based on the target system.

Figure 13 app Stochastic will automatically determine if the Swift standard library in the APP bundle is deleted based on the target system

The Always Embed Swift Standard Library tells the build system what to do. Set it to YES whenever your target references Swift files or libraries, such as the main project that uses the Swift static library, or if your target is a test project that references Swift code, You also need to set it to YES. In addition, I have tested that if you add a Swift file to a pure ObjC project, Xcode automatically sets this option to YES.

Figure 14 setAlways Embed Swift Standard Library

Reference:

  • stackoverflow.com/a/55365318
  • stackoverflow.com/a/26949219
  • Onevcat.com/2019/02/swi…
  • Swift.org/blog/abi-st…
  • Swift.org/blog/abi-st…
  • Developer.apple.com/documentati…

6. Modularization/componentization

As mentioned above, my company’s iOS project adopts a modular architecture, and modules are dependent on each other. Typically, the upper modules depend on the lower modules, as shown in Figure 4.

To illustrate the concept of modules, in our project an ObjC module is a combination of.a static library +.h header files + bundle resource files.

6.1 ObjC Module Invokes Swift Module

As mentioned earlier, ObjC calls Swift code by simply importing the header file xxx-swift.h that is automatically generated when the Swift module is compiled.

For example, the ObjCLibA module calls the SwiftLibA module:

#import "ObjCLibA.h"
#import <SwiftLibA/SwiftLibA-Swift.h>

@implementation ObjCLibA

- (void)sayHello {
    [[SwiftLibA new] sayHelloWithName:@"ObjCLibA"];
}

@end
Copy the code

This is fine, but considering that modules on a continuous delivery platform are compiled independently, as in the above example, if the module ObjCLibA is compiled separately, the header file will not be found: ‘SwiftLibA/SwiftLibA- swift.h ‘file not found.

ObjCLibA calls SwiftLibA, (a) compiling the main project is ok, (b) but compiling ObjCLibA alone is wrong

This is because the swiftliba-swift. h file is the product of compiling the SwiftLibA module and is generated in the Build directory, not in the directory where the project code resides. We have already discussed this point and will not repeat it here.

We all know that there are two ways to import headers using #import directives, #import “xxx.h” and #import

. The compiler will search for headers according to different directives when compiling ObjC code, in the case of the former, in the project (source code) directory. For the latter, search to the directory indicated by the environment variable or the specified directory.

Swiftliba-swift. h file is generated according to the Swift code public API we wrote, so every time we change the Swift code public API, it will be updated, so, Each time we build this module, we can copy the newly generated file to the source directory (this file needs to be added to version control and submitted with other code), and then add the new Path to the Header Search Path of the ObjC module. Additionally, Change the way header files are imported in ObjC modules to double quotes.

The full script is as follows:



generated_header_file=${DERIVED_SOURCES_DIR}/*-Swift.h
include_dir=${BUILT_PRODUCTS_DIR}/include/${PRODUCT_MODULE_NAME}/

#Copy the xxx-swift header generated by the compiler into the include directory under the build directory
mkdir -p ${include_dir}
cp ${generated_header_file} ${include_dir}

#Remove the compiler version number from the header comment of the xxx-swift.h file
sed -i "" "s/^\/\/ Generated by Apple.*$/\/\/ Generated by Apple/g" ${generated_header_file}

#Copy the xxx-swift. h file to the project source directoryheader_file_in_proj=${SRCROOT}/${PROJECT}-Swift.h needs_copy=true if [ -f "$header_file_in_proj" ]; Then echo "${header_FILe_in_PROj} already exists "new_content=$(cat ${generated_header_file}) old_content=$(cat ${header_file_in_proj}) if [ "$new_content" = "$old_content" ]; Then echo "file content is the same, no need to Copy: " echo "${generated_header_file} " echo "${header_file_in_proj} " needs_copy=false fi fi if [ "$needs_copy" = true ] ; Then echo "file contents are inconsistent. Copy:" echo"  " echo "${generated_header_file} " echo "${header_file_in_proj} " cp ${generated_header_file} ${header_file_in_proj} fiCopy the code

Figure 16 copies the header file generated by the compiler to the source directory

Reference:

  • Docs.microsoft.com/en-us/cpp/p…

6.2 Swift Module Invokes the Swift Module

The ObjC module calls the Swift module, so what if the Swift module calls the Swift module? Could there be a similar problem?

SwiftLibB: SwiftLibB: SwiftLibB

- MainProject
  - ObjCLibA
  - SwiftLibA
  - SwiftLibB
Copy the code

Then we call the API in module SwiftLibB in module SwiftLibA:

import Foundation
import SwiftLibB

@objcMembers
public class SwiftLibA: NSObject {
    
    public func sayHello(name: String) {
        SwiftLibB().sayHello(name: name)
        print("Hello, this is " + name + "!")
        print("-- Printed by SwiftLibA")}}Copy the code

This is fine if you compile the main project, but if you compile the module SwiftLibA separately, you will get an error: No such module ‘SwiftLibB’.

(a) Compiling the main project is ok, (b) but compiling the module SwiftLibA alone is wrong

This seems to be the same problem as ObjC module calling Swift module, but we need to know that Swift has no concept of header file, so how does Swift expose public API?

Whereas C-based languages use manually written headers to provide public interfaces, Swift describes a library interface in a file called swiftModule, This SwiftModule file is automatically generated by the compiler. Swiftlibb. swiftModule = swiftlibb. swiftModule = swiftlibb. swiftModule = swiftlibb. swiftModule = swiftlibb. swiftModule = swiftlibb. swiftModule Swiftmodule file and SwiftDoc file. The SwiftModule file and swiftDoc file are binary files, which can be viewed by decomcompiling tools. The SwiftModule file contains the module information, while the SwiftDoc file contains the comments in the source code.

Figure 18 SwiftModule file in the Build directory

You might think that you would just export the swiftModule files to the source directory, set the SwiftLibA import path, and add the files to git version control.

Yes, I thought so at first, and then I did it. There was a problem with compiling SwiftLibA separately, but after submitting to git remote repository, the SwiftLibA module on continuous delivery platform compiled incorrectly:

. Error: Module compiled with Swift 5.1 cannot be imported by the Swift 5.1.2 compiler...Copy the code

Module Stability

The swiftModule file is bound to the compiler version. Apple did not provide a solution until Swift 5.1 was released. Apple has also solved an important problem, Module Stability, that is, the problem we meet here.

ABI Stability addresses runtime compatibility with code from different Swift versions, while Module Stability addresses compile-time compatibility with code from different Swift versions. Binary Frameworks in Swift ABI Stability and More and WWDC 2019 Plan for Module stability, Update on Module Stability and Module Interface Files.

Module Stability on swift.org’s blog

For Module Stability, The solution Apple provides is swiftInterface file. Swiftinterface file is a supplement to SwiftModule. It is a text file that describes the public interface of Module. No compiler version restrictions. For example, if you compile a library with the Swift 5.0 compiler, its SwiftInterface file can be used with the Swift 5.1 compiler.

Now open SwiftLibB’s Build Setting, go to Build Options -> Build Libraries for Distribution and set it to YES. Take a look at the swiftLibb. swiftModule generated in the Build directory. There are several more SwiftInterface files.

Figure 20Build Libraries for Distributionoptions

Figure 21 is automatically generated by the compilerswiftinterfacefile

We can open the SwiftInterface file and compare it to the source code. It’s actually a Swift header file.

The source code:

import Foundation

@objcMembers
public class SwiftLibB: NSObject {

    public func sayHello(name: String) {
        print("Hello, this is " + name + "!")
        print("-- Printed by SwiftLibB")}}Copy the code

Contents of the swiftInterface file:

// swift-interface-format-version: 1.0
// swift-compiler-version: Apple Swift version 5.1 (swiftlang-1100.0.270.13 clang-1100.0.33.7)
// swift-module-flags: -target x86_64-apple-ios13.0-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -Onone -module-name SwiftLibB
import Foundation
import Swift
@objc @objcMembers public class SwiftLibB : ObjectiveC.NSObject {
  @objc public func sayHello(name: Swift.String)
  @objc override dynamic public init()
  @objc deinit
}

Copy the code

To enable separate compilation of SwiftLibA, copy swiftlibb. swiftModule into the source directory as we did with xx-swift.h. Then add the new path to SwiftLibA’s Build Setting -> Swift Compiler-Search Paths -> Import Paths.

Figure 22 Add the swiftModule file path to SwiftLibA’s Import Paths

A disadvantage of this approach to modularity/componentization is that many different CPU architectures need to be considered each time a Swift module is compiled.

In addition to this solution, there are two other solutions to solve the problem of dependencies between Swift modules:

  • We can also use SwiftLibB as a subproject of SwiftLibA (becausexcodeprojFile can be referenced as reference), and then set the compile dependency, but not setLink Binary With LibrariesThis ensures that SwiftLibA compiles but does not duplicate links.
  • Module Stability is not supported until Swift 5 is officially released. There are Swift developers using ObjC to package Swift layer. The ObjC header is then used as the public interface (see Swift 5 Module Stability Workaround for Binary Frameworks).

reference

  • Medium.com/better-prog…
  • Andelf. Making. IO/blog / 2014/0…
  • stackoverflow.com/a/58656323
  • Swift.org/blog/abi-st…
  • Forums.swift.org/t/plan-for-…
  • Forums.swift.org/t/update-on…
  • Developer.apple.com/videos/play…
  • Instabug.com/blog/swift-…
  • Medium.com/swiftify/sw…

6.3 Swift Module Invokes ObjC Module

Swift calls to ObjC can be done via objective-c bridging headers if they’re in the same APP target, but what about calls across modules? How does the Swift module call ObjC module?

According to the Official Apple documentation, you cannot use the Bridging header in the Library or Framework, but should use the umbrella header instead.

LLVM Module and Umbrella Header

What is umbrella Header? This brings us to the concept of the LLVM Module, which was introduced to solve the problems of the traditional #include and #import header mechanisms. In other words, it is a new header management mechanism, which is described in detail in the official LLVM documentation.

Modules can be imported from ObjC with the @import directive, and from Swift with the import keyword.

One of the most important files in the Module mechanism is the Module Map file, which describes the logical correspondence between header files and Module structures.

The crucial link between modules and headers is described by a module map, which describes how a collection of existing headers maps on to the (logical) structure of a module. For example, one could imagine a module std covering the C standard library. Each of the C standard library headers (stdio.h, stdlib.h, math.h, etc.) would contribute to the std module, by placing their respective APIs into the corresponding submodule (std.io, std.lib, std.math, etc.). Having a list of the headers that are part of the std module allows the compiler to build the std module as a standalone entity, and having the mapping from header names to (sub)modules allows the automatic translation of #include directives to module imports.

Module maps are specified as separate files (each named module.modulemap) alongside the headers they describe, which allows them to be added to existing software libraries without having to change the library headers themselves (in most cases [2]).

Each library will have a corresponding module. moduleMap file, which declares the header files to reference, and these header files will be placed next to the module. moduleMap file.

The module map language describes the mapping from header files to the logical structure of modules. To enable support for using a library as a module, one must write a module.modulemap file for that library. The module.modulemap file is placed alongside the header files themselves, and is written in the module map language described below.

A C library module map file might look like this:

module std [system] [extern_c] { module assert { textual header "assert.h" header "bits/assert-decls.h" export * } module complex { header "complex.h" export * } module ctype { header "ctype.h" export * } module errno { header "errno.h" header "sys/errno.h" export * } module fenv { header "fenv.h" export * } // ... more headers follow... }Copy the code

Modulemap is implemented using the Module Map language, which has reserved words such as umbrella to declare umbrella header. Umbrella Header can include all header files in a directory so that developers can use all of the library apis in a single import.

A header with the umbrella specifier is called an umbrella header. An umbrella header includes all of the headers within its directory (and any subdirectories), and is typically used (in the #include world) to easily access the full API provided by a particular library. With modules, an umbrella header is a convenient shortcut that eliminates the need to write out header declarations for every library header. A given directory can only contain a single umbrella header.

When you create a Framework, the module directory will be set to YES by default. When you compile the Framework, you can see the module directory automatically generated under the build directory. The Module directory contains the automatically created ModuleMap file that references the automatically created Umbrella header. However, if you are creating a static library, you will need to manually create the ModuleMap file and umbrella header for the module to reference.

Next we create an ObjCLibB module and let the SwiftLibA module call it.

The first thing to do is to create an umbrella header file and a ModuleMap file for the ObjCLibB module, and then add the moduleMap file’s path to the Import Paths of SwiftLibA. Add the umbrella Header file path to SwiftLibA’s Header Search Paths and you’re done.

Figure 23 Creating an umbrella Header file

Figure 24 Creating the ModuleMap file

Figure 25 Add the moduleMap file’s path to SwiftLibA’s Import Paths

Figure 26 Add umbrella Header file path to SwiftLibA header Search Paths

If your Swift module is calling an objC-Swift mashup, the same can be done. The core is to wrap the C-based header with the ModuleMap and umbrella Header.

Reference:

  • Samsymons.com/blog/unders…
  • Medium.com/swift-and-i…
  • Medium.com/allatonepla…
  • Clang.llvm.org/docs/Module…
  • Hechen. Xyz/post/swift -…

7. Debug problems

If your main project is a pure ObjC implementation, then when you debug code in the Swift module at a breakpoint, you will not see the variable values, even if you print them using the LLDB command on the console.

(lldb) po name
Cannot create Swift scratch context (couldn't load the Swift stdlib)Cannot create Swift scratch context (couldn't load the Swift stdlib)Shared Swift state for MainProject could not be initialized.
The REPL and expressions are unavailable.

Copy the code

Figure 27. Variable values cannot be seen while debugging Swift code

This is because there is no Swift code in the main project, so there are no Swift related environment and Settings options. The solution is to create a new Swift file in the main project.

Third, summary

With the arrival of Swift 5, we finally see the long-awaited ABI stability and believe that more modern and secure Swift will become more and more popular. In addition, LLVM Module is an unavoidable topic when landing Swift in modularization/componentization project. LLVM Module changes the header file mechanism of traditional C-based language and replaces it with Module thinking. As technology advances and productivity advances, we look forward to Swift’s ability to further improve our development efficiency and programming experience in the future.