Swift is ABI stable after version 5.0, which means the binary interface is stable. This means that binary compiled from Swift5 and above can run on Swift5 and above runtime. The environment can be unified at the system level, eliminating the need to integrate multiple Swift runtime versions at packaging time. Swift 5.1 is also a big leap forward. Swift 5.1 supports module stability, which is also significant for Swift. Swift secondary libraries (Framework) compiled before Swift 5.1 can only run in the corresponding compiler chain version, Module Stability means that Swift framework compiled by Swift 5.1 and later versions can be integrated and compiled by Swift 5.1 and later compilation chain, which lays a foundation for the expansion of Swift binary library.

As a developer of Swift Framework, I have been trying to adapt 5.1 and release the corresponding binary libraries after the release of Swift 5.1. The following is a record of the adaptation process and problems of Swift Module Stability.

Problems encountered before module Stability version compatibility: Framework execution compiled in a version of the Swift compiler runs in the corresponding Swift compiler version, such as Framwork compiled in Xcode10.x(Swift4.2 version), which can only run in Xcode10.x. The following error is thrown if run under a different version of the compilation:

Module compiled with Swift 5.1 cannot be imported by the Swift 5.1.2 compiler

Module stability is easy to start with. Set build Libraries for Distribution to YES in the Build Setting.

However, simply building Libraries for Distribution does not necessarily solve all problems. If you use the @objc keyword modifier in the Swift extension, Or protocols that implement UIKit (such as UITableViewDelegate implemented in Extention) will throw the following error at compile time:

@objc’ class method in extension of subclass of Class X requires iOS 13.0.0

This error is a compile-time limitation by Apple, and using the @objc method in an extension of the @objc class requires changes to the Objective-C runtime that are only available in iOS 13 and later when creating a framework for distribution. The solution is to move these methods into the class definition itself, or the @objc keyword (UIKit’s protocol implementation can only be defined into the class itself).

If you are using Cocoapods to rely on third-party libraries, make sure that the libraries you rely on have module stabilization enabled. If you are relying on third-party libraries that do not have module stabilization enabled, add the following code to the end of your Podfile:

post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
    end
  end
end
Copy the code

Set BUILD_LIBRARY_FOR_DISTRIBUTION on all third party libraries.

Even if BUILD_LIBRARY_FOR_DISTRIBUTION is enabled, the following error still occurs:

Failed to build module ‘MyModule’ from its module interface; The compiler that produced it, ‘Apple Swift version 5.1.3 power-4.2 (Swiftlang-1100.0.282.1 clang-1100.0.33.15)’, may have used features that aren’t supported by this compiler, ‘Apple Swift Version 5.3 Effective 4.2 (Swiftlang-1200.0.28.1 Clang-1200.0.30.1)’

This is because the minimum Swift version supported by Module Stability is 5.1, and you need to set the Swift version to Swift 5.

Module stability is compatible with the environment because it is forward compatible, not backward compatible:

  • Xcode 11 or later
  • Swift 5.1 and later versions
  • IOS 11 or later

The following is a list of difficult problems that may be encountered in the adaptation process and solutions:

error Wrong type Error description The solution
Redundant conformance of x to NSObjectProtocol Error – Thrown on dynamic linking Because this class is alreadyNSObjectSubclass, but complyNSObjectProtocolagreement Check protocol consistency of classes and remove redundant onesNSObjectProtocolThe agreement.
Use of unimplemented initializer ‘init()’ for class Error – Thrown on dynamic linking Classes exposed by the OC ABI need to be provided publiclyinitimplementation providepublicModification of theinitFunction:override public init()
@objc’ class method in extension of subclass of Class XThe requires iOS 13.0.0 error The interoperability rules for OC have changed since iOS 13.0.0. It is not currently supported in class extensions@objcInteroperability.Swift BBSOpen questions on Move these methods to the class definition itself, or@objcKeyword (UIKitProtocol implementations can only be defined in the class itself.
scoped imports are not yet supported in module interfaces warning Learn more at this link:nshipster.com/import/ Import modules instead of specific declarations such as: changesimport class MyModule.MyClassforimport MyModule
Can’t use framework compiled with Swift 5.2 in Swift 5.1.3 project Error – Thrown when linking dynamic libraries Module stability is forward compatibility, not backward compatibility Upgrade your Xcode to Xcode11.4 to integrate the Framework, or lower your Xcode to Xcode11.3 to repackage the framework
Incompatible module Error- Thrown when linking dynamic libraries Modules built for the iOS emulator share the same Arch slice as the new M1. Build by specifying the following build setting: EXCLUDED_ARCHS[SDK =iphonesimulator*] = arm64

PS: There are too many holes to build SDK with Swift. Now there are still a lot of holes to fill, and the benefits are far less than the costs. If I choose to develop SDK with Swift again, I will never use Swift.