What Is the "@Exported" Attribute in Swift

What is the @exported attribute in Swift

This attribute officially does not exist. Unofficially, however, it is a way of opening a sub-framework's symbols into your own framework's scope and exporting them as though they were yours. For example, a testing framework might wish to declare an @exported XCTest somewhere so all it takes to use the framework is just import TestFramework.

Be warned, though the attribute is compatible with most swift versions and should compile fine, it will break code completion in creative ways on each individual build of Xcode - probably a big reason why it is not an official feature yet.

What is import func, struct, class, and @_exported in Swift?

You can import only a specific part of a module, not a whole module:

Providing more detail limits which symbols are imported—you can specify a specific submodule or a specific declaration within a module or submodule. When this detailed form is used, only the imported symbol (and not the module that declares it) is made available in the current scope.

From Import Declaration

For example import func POSIX.isatty will import function isatty from module POSIX instead of importing the whole module POSIX (which is BIG).

The @_exported attribute starts with an underscore. That means it's a private Swift attribute. Not a feature, an implementation detail.
In short, this attribute lets you export a symbol from another module as if it were from your module.

exported: true' has no effect in '_specialize' attribute in Xcode 12.5

I have resolved the issue with running pod update instead of pointing to a specific version in my Podfile

Otherwise, you could also follow what @coryhowell pointed out,

removed the pod and added it as a Swift Package (Version 1.4.0)

Podfile

platform :ios, '11.4'
use_frameworks!
inhibit_all_warnings!

target 'myAppp' do
pod 'Alamofire', '~> 4.8.1'
pod 'CryptoSwift'
end

Podfile.lock - auto-created, then pointed to latest version of the CryptoSwift

PODS:
- Alamofire (4.8.2)
- Countly (20.11.1):
- Countly/Core (= 20.11.1)
- Countly/Core (20.11.1)
- Crashlytics (3.12.0):
- Fabric (~> 1.9.0)
- CryptoSwift (1.4.0)
- Device (3.1.2)
- Fabric (1.9.0)

..
...
not showing all lines
....
......

Should an IBOutlet property be marked nullable or nonnull?

If your class is written in Swift, you can't use a non optional property because otherwise the compiler is going to complain that the property is never initialized. That's why Apple recommends to declare it as an implicitly unwrapped optional, because once your object has been initialized, you know for sure that the property contains a value (unless you have a dangling outlet, which can happen by the way...)

When exporting from Objective-C, you can mark it as nonnull and it will appear in Swift as a non optional property which is fine in that case. Note that you can't use both nonnull and weak.

So you can either do :

@property (nonatomic, strong, nonnull) IBOutlet UIView *subview;
// Exported to Swift as @IBOutlet var subview: UIView

or

@property (nonatomic, weak, nullable) IBOutlet UIView *subview;
// Exported to Swift as @IBOutlet weak var subview: UIView?

If for some reason you still want the property to be exported to Swift as an implicitly unwrapped optional, you can mark the property as null_resettable or null_unspecified. That's not really what they are meant for but it will still produce the desired result. See this blog post for more on these annotations.

@property (nonatomic, weak, null_unspecified) IBOutlet UIView *subview;
// Exported to Swift as @IBOutlet weak var subview: UIView!

How to make a Swift String enum available in Objective-C?

From the Xcode 6.3 release notes (emphasis added):

Swift Language Enhancements

...

Swift enums can now be exported to Objective-C using the @objc
attribute. @objc enums must declare an integer raw type, and cannot be
generic or use associated values. Because Objective-C enums are not
namespaced, enum cases are imported into Objective-C as the
concatenation of the enum name and case name.

Access control in swift 4

My original answer (shown below) is now mostly outdated – the beginnings of the resilience model are to be implemented in Swift 4.2 with the introduction of the @inlinable and @usableFromInline attributes, corresponding to the old @_inlineable and @_versioned attributes.

In addition, and more importantly, the rule for what default arguments of publically accessible functions can reference has changed again. To recap the previous rules:

  • In Swift 3 there was no enforcement of what access level such default argument expressions could reference (allowing your first example where defaultValue is internal).

  • In Swift 4, such a default argument could only refer to declarations exposed as a part of the module's interface, including those that aren't otherwise directly visible to users in another module (i.e @_versioned internal).

However in Swift 4.2, with the implementation of SE-0193, the rule is now that the default argument expression of a publicly accessible function can only refer to publicly accessible declarations (not even @inlinable internal or @usableFromInline internal).

I believe this is paving the way for the displaying of default argument expressions in a module's generated interface file. Currently Swift just shows an unhelpful = default, but I believe this will change to actually show the default argument. This can only realistically happen with this new access-control restriction in place (Edit: This is now happening).


Old answer (Swift 4)

This change is due to the work towards a resilience model that is already available via underscored attributes (@_inlineable, @_versioned, @_fixed_layout), but is yet to be officially finalised (so you probably shouldn't be using these attributes yourself yet). You can read about the full proposed details of the resilience model here, as well as the the Swift evolution discussion on it here.

In short, an inlineable function is one whose implementation, as well as declaration, is exposed as a part of a module's interface and can therefore be inlined when called from another module. An inlineable function must therefore also be publically accessible to begin with (i.e public or higher).

What you're running into is a change that makes default argument expressions for publically accessible functions inlineable, meaning that they must be available to be evaluated directly in the calling module's binary. This reduces the overhead of calling a function with default parameter values from another module, as the compiler no longer needs to do a function call for each default argument; it already knows the implementation.

I don't believe this change is officially documented in the release of Swift 4 itself, but it is confirmed by Swift compiler engineer Slava Pestov, who says:

Swift 3.1 added resilience diagnostics for inlineable code, which is not an officially supported feature, but in Swift 4 we switched these checks on for default argument expressions as well.

So if you have a publically accessible function with a default argument expression (such as MyClass.defaultValue in your case), that expression can now only refer to things that are also a part of that module's interface. So you need to make defaultValue publically accessible.

Unfortunately, there's currently no way to make a private function's declaration part of a module's interface (which would allow for your usage of it in a default argument expression). The attribute that would facilitate this is @_versioned, but it is forbidden with (file)private due to the following reasons given by Slava Pestov:

It would be a trivial change to allow @_versioned on private and
fileprivate declarations, but there are two pitfalls to keep in mind:

  • Private symbols are mangled with a ‘discriminator’ which is basically a hash of the file name. So now it would be part of the ABI,
    which seems fragile — you can’t move the private function to another
    source file, or rename the source file.

  • Similarly, right now a @_versioned function becoming public is an ABI compatible change. This would no longer work if you could have
    private @_versioned functions, because the symbol name would change if
    it became public.


For these reasons we decided against “private versioned” as a concept.
I feel like internal is enough here.

You could achieve this with a @_versioned var defaultValue though:

open class MyClass {

private let value: Int

@_versioned static var defaultValue: Int {
return 10
}

public init(value: Int = MyClass.defaultValue) {
self.value = value
}
}

The declaration of MyClass.defaultValue is now exported as a part of the module's interface, but still cannot be directly called from another module's code (as it's internal). However, the compiler of that module can now call it when evaluating the default argument expression. But, as said earlier, you probably shouldn't be using an underscored attribute here; you should wait until the resilience model has been finalised.

Swift to Objective-C header does not contain Swift classes

Here's how I have gotten it to work. You can see a more large-scale answer here.

Change this:

class HelloWorld {    
func hello() {
println("hello world")
}
}

To:

@objc class HelloWorld { 

class func newInstance() -> HelloWorld {
return HelloWorld()
}

func hello() {
println("hello world")
}
}

Then, In your ObjC file:

#import "TestApp-Swift.h"

And call like this:

HelloWorld * helloWorld = [HelloWorld newInstance];
[helloWorld hello];


Related Topics



Leave a reply



Submit