364 lines
9.8 KiB
ReStructuredText
364 lines
9.8 KiB
ReStructuredText
|
================================================
|
||
|
API Notes: Annotations Without Modifying Headers
|
||
|
================================================
|
||
|
|
||
|
**The Problem:** You have headers you want to use, but you also want to add
|
||
|
extra information to the API. You don't want to put that information in the
|
||
|
headers themselves --- perhaps because you want to keep them clean for other
|
||
|
clients, or perhaps because they're from some open source project and you don't
|
||
|
want to modify them at all.
|
||
|
|
||
|
**Incomplete solution:** Redeclare all the interesting parts of the API in your
|
||
|
own header and add the attributes you want. Unfortunately, this:
|
||
|
|
||
|
* doesn't work with attributes that must be present on a definition
|
||
|
* doesn't allow changing the definition in other ways
|
||
|
* requires your header to be included in any client code to take effect
|
||
|
|
||
|
**Better solution:** Provide a "sidecar" file with the information you want to
|
||
|
add, and have that automatically get picked up by the module-building logic in
|
||
|
the compiler.
|
||
|
|
||
|
That's API notes.
|
||
|
|
||
|
API notes use a YAML-based file format. YAML is a format best explained by
|
||
|
example, so here is a `small example`__ from the compiler test suite of API
|
||
|
notes for a hypothetical "SomeKit" framework.
|
||
|
|
||
|
__ test/APINotes/Inputs/Frameworks/SomeKit.framework/Headers/SomeKit.apinotes
|
||
|
|
||
|
|
||
|
Usage
|
||
|
=====
|
||
|
|
||
|
API notes files are found relative to the module map that defines a module,
|
||
|
under the name "SomeKit.apinotes" for a module named "SomeKit". Additionally, a
|
||
|
file named "SomeKit_private.apinotes" will also be picked up to go with a
|
||
|
private module map. For bare modules these two files will be in the same
|
||
|
directory as the corresponding module map; for framework modules, they should
|
||
|
be placed in the Headers and PrivateHeaders directories, respectively. The
|
||
|
module map for a private top-level framework module should be placed in the
|
||
|
PrivateHeaders directory as well, though it does not need an additional
|
||
|
"_private" suffix on its name.
|
||
|
|
||
|
Clang will search for API notes files next to module maps only when passed the
|
||
|
``-fapi-notes-modules`` option.
|
||
|
|
||
|
|
||
|
Limitations
|
||
|
===========
|
||
|
|
||
|
- Since they're identified by module name, API notes cannot be used to modify
|
||
|
arbitrary textual headers.
|
||
|
|
||
|
|
||
|
"Versioned" API Notes
|
||
|
=====================
|
||
|
|
||
|
Many API notes affect how a C API is imported into Swift. In order to change
|
||
|
that behavior while still remaining backwards-compatible, API notes can be
|
||
|
selectively applied based on the Swift compatibility version provided to the
|
||
|
compiler (e.g. ``-fapi-notes-swift-version=5``). The rule is that an
|
||
|
explicitly-versioned API note applies to that version *and all earlier
|
||
|
versions,* and any applicable explicitly-versioned API note takes precedence
|
||
|
over an unversioned API note.
|
||
|
|
||
|
|
||
|
Reference
|
||
|
=========
|
||
|
|
||
|
An API notes file contains a YAML dictionary with the following top-level
|
||
|
entries:
|
||
|
|
||
|
:Name:
|
||
|
|
||
|
The name of the module (the framework name, for frameworks). Note that this
|
||
|
is always the name of a top-level module, even within a private API notes
|
||
|
file.
|
||
|
|
||
|
::
|
||
|
|
||
|
Name: MyFramework
|
||
|
|
||
|
:Classes, Protocols, Tags, Typedefs, Globals, Enumerators, Functions:
|
||
|
|
||
|
Arrays of top-level declarations. Each entry in the array must have a
|
||
|
'Name' key with its Objective-C name. "Tags" refers to structs, enums, and
|
||
|
unions; "Enumerators" refers to enum cases.
|
||
|
|
||
|
::
|
||
|
|
||
|
Classes:
|
||
|
- Name: MyController
|
||
|
…
|
||
|
- Name: MyView
|
||
|
…
|
||
|
|
||
|
:SwiftVersions:
|
||
|
|
||
|
Contains explicit information for backwards compatibility. Each entry in
|
||
|
the array contains a 'Version' key, which should be set to '4' for
|
||
|
annotations that only apply to Swift 4 mode and earlier. The other entries
|
||
|
in this dictionary are the same declaration entries as at the top level:
|
||
|
Classes, Protocols, Tags, Typedefs, Globals, Enumerators, and Functions.
|
||
|
|
||
|
::
|
||
|
|
||
|
SwiftVersions:
|
||
|
- Version: 4
|
||
|
Classes: …
|
||
|
Protocols: …
|
||
|
|
||
|
Each entry under 'Classes' and 'Protocols' can contain "Methods" and
|
||
|
"Properties" arrays, in addition to the attributes described below:
|
||
|
|
||
|
:Methods:
|
||
|
|
||
|
Identified by 'Selector' and 'MethodKind'; the MethodKind is either
|
||
|
"Instance" or "Class".
|
||
|
|
||
|
::
|
||
|
|
||
|
Classes:
|
||
|
- Name: UIViewController
|
||
|
Methods:
|
||
|
- Selector: "presentViewController:animated:"
|
||
|
MethodKind: Instance
|
||
|
…
|
||
|
|
||
|
:Properties:
|
||
|
|
||
|
Identified by 'Name' and 'PropertyKind'; the PropertyKind is also either
|
||
|
"Instance" or "Class".
|
||
|
|
||
|
::
|
||
|
|
||
|
Classes:
|
||
|
- Name: UIView
|
||
|
Properties:
|
||
|
- Name: subviews
|
||
|
PropertyKind: Instance
|
||
|
…
|
||
|
|
||
|
Each declaration supports the following annotations (if relevant to that
|
||
|
declaration kind), all of which are optional:
|
||
|
|
||
|
:SwiftName:
|
||
|
|
||
|
Equivalent to ``NS_SWIFT_NAME``. For a method, must include the full Swift name
|
||
|
with all arguments. Use "_" to omit an argument label.
|
||
|
|
||
|
::
|
||
|
|
||
|
- Selector: "presentViewController:animated:"
|
||
|
MethodKind: Instance
|
||
|
SwiftName: "present(_:animated:)"
|
||
|
|
||
|
- Class: NSBundle
|
||
|
SwiftName: Bundle
|
||
|
|
||
|
:Availability, AvailabilityMsg:
|
||
|
|
||
|
A value of "nonswift" is equivalent to ``NS_SWIFT_UNAVAILABLE``. A value of
|
||
|
"available" can be used in the "SwiftVersions" section to undo the effect of
|
||
|
"nonswift".
|
||
|
|
||
|
::
|
||
|
|
||
|
- Selector: "dealloc"
|
||
|
MethodKind: Instance
|
||
|
Availability: nonswift
|
||
|
AvailabilityMsg: "prefer 'deinit'"
|
||
|
|
||
|
:SwiftPrivate:
|
||
|
|
||
|
Equivalent to NS_REFINED_FOR_SWIFT.
|
||
|
|
||
|
::
|
||
|
|
||
|
- Name: CGColorEqualToColor
|
||
|
SwiftPrivate: true
|
||
|
|
||
|
:Nullability:
|
||
|
|
||
|
Used for properties and globals. There are four options, identified by their
|
||
|
initials:
|
||
|
|
||
|
- ``Nonnull`` or ``N`` (corresponding to ``_Nonnull``)
|
||
|
- ``Optional`` or ``O`` (corresponding to ``_Nullable``)
|
||
|
- ``Unspecified`` or ``U`` (corresponding to ``_Null_unspecified``)
|
||
|
- ``Scalar`` or ``S`` (deprecated)
|
||
|
|
||
|
Note that 'Nullability' is overridden by 'Type', even in a "SwiftVersions"
|
||
|
section.
|
||
|
|
||
|
.. note::
|
||
|
|
||
|
'Nullability' can also be used to describe the argument types of methods
|
||
|
and functions, but this usage is deprecated in favor of 'Parameters' (see
|
||
|
below).
|
||
|
|
||
|
::
|
||
|
|
||
|
- Name: dataSource
|
||
|
Nullability: O
|
||
|
|
||
|
:NullabilityOfRet:
|
||
|
|
||
|
Used for methods and functions. Describes the nullability of the return type.
|
||
|
|
||
|
Note that 'NullabilityOfRet' is overridden by 'ResultType', even in a
|
||
|
"SwiftVersions" section.
|
||
|
|
||
|
.. warning::
|
||
|
|
||
|
Due to a compiler bug, 'NullabilityOfRet' may change nullability of the
|
||
|
parameters as well (rdar://30544062). Avoid using it and instead use
|
||
|
'ResultType' and specify the return type along with a nullability
|
||
|
annotation (see documentation for 'ResultType').
|
||
|
|
||
|
::
|
||
|
|
||
|
- Selector: superclass
|
||
|
MethodKind: Class
|
||
|
NullabilityOfRet: O
|
||
|
|
||
|
:Type:
|
||
|
|
||
|
Used for properties and globals. This completely overrides the type of the
|
||
|
declaration; it should ideally only be used for Swift backwards
|
||
|
compatibility, when existing type information has been made more precise in a
|
||
|
header. Prefer 'Nullability' and other annotations when possible.
|
||
|
|
||
|
We parse the specified type as if it appeared at the location of the
|
||
|
declaration whose type is being modified. Macros are not available and
|
||
|
nullability must be applied explicitly (even in an ``NS_ASSUME_NONNULL_BEGIN``
|
||
|
section).
|
||
|
|
||
|
::
|
||
|
|
||
|
- Name: delegate
|
||
|
PropertyKind: Instance
|
||
|
Type: "id"
|
||
|
|
||
|
:ResultType:
|
||
|
|
||
|
Used for methods and functions. This completely overrides the return type; it
|
||
|
should ideally only be used for Swift backwards compatibility, when existing
|
||
|
type information has been made more precise in a header.
|
||
|
|
||
|
We parse the specified type as if it appeared at the location of the
|
||
|
declaration whose type is being modified. Macros are not available and
|
||
|
nullability must be applied explicitly (even in an ``NS_ASSUME_NONNULL_BEGIN``
|
||
|
section).
|
||
|
|
||
|
::
|
||
|
|
||
|
- Selector: "subviews"
|
||
|
MethodKind: Instance
|
||
|
ResultType: "NSArray * _Nonnull"
|
||
|
|
||
|
:SwiftImportAsAccessors:
|
||
|
|
||
|
Used for properties. If true, the property will be exposed in Swift as its
|
||
|
accessor methods, rather than as a computed property using ``var``.
|
||
|
|
||
|
::
|
||
|
|
||
|
- Name: currentContext
|
||
|
PropertyKind: Class
|
||
|
SwiftImportAsAccessors: true
|
||
|
|
||
|
:NSErrorDomain:
|
||
|
|
||
|
Used for ``NSError`` code enums. The value is the name of the associated
|
||
|
domain ``NSString`` constant; an empty string (``""``) means the enum is a
|
||
|
normal enum rather than an error code.
|
||
|
|
||
|
::
|
||
|
|
||
|
- Name: MKErrorCode
|
||
|
NSErrorDomain: MKErrorDomain
|
||
|
|
||
|
:SwiftWrapper:
|
||
|
|
||
|
Controls ``NS_STRING_ENUM`` and ``NS_EXTENSIBLE_STRING_ENUM``. There are three
|
||
|
options:
|
||
|
|
||
|
- "struct" (extensible)
|
||
|
- "enum"
|
||
|
- "none"
|
||
|
|
||
|
Note that even an "enum" wrapper is still presented as a struct in Swift;
|
||
|
it's just a "more enum-like" struct.
|
||
|
|
||
|
::
|
||
|
|
||
|
- Name: AVMediaType
|
||
|
SwiftWrapper: none
|
||
|
|
||
|
:EnumKind:
|
||
|
|
||
|
Has the same effect as ``NS_ENUM`` and ``NS_OPTIONS``. There are four options:
|
||
|
|
||
|
- "NSEnum" / "CFEnum"
|
||
|
- "NSClosedEnum" / "CFClosedEnum"
|
||
|
- "NSOptions" / "CFOptions"
|
||
|
- "none"
|
||
|
|
||
|
::
|
||
|
|
||
|
- Name: GKPhotoSize
|
||
|
EnumKind: none
|
||
|
|
||
|
:Parameters:
|
||
|
|
||
|
Used for methods and functions. Parameters are identified by a 0-based
|
||
|
'Position' and support the 'Nullability', 'NoEscape', and 'Type' keys.
|
||
|
|
||
|
.. note::
|
||
|
|
||
|
Using 'Parameters' within a parameter entry to describe the parameters of a
|
||
|
block is not implemented. Use 'Type' on the entire parameter instead.
|
||
|
|
||
|
::
|
||
|
|
||
|
- Selector: "isEqual:"
|
||
|
MethodKind: Instance
|
||
|
Parameters:
|
||
|
- Position: 0
|
||
|
Nullability: O
|
||
|
|
||
|
:NoEscape:
|
||
|
|
||
|
Used only for block parameters. Equivalent to ``NS_NOESCAPE``.
|
||
|
|
||
|
::
|
||
|
|
||
|
- Name: dispatch_sync
|
||
|
Parameters:
|
||
|
- Position: 0
|
||
|
NoEscape: true
|
||
|
|
||
|
:SwiftBridge:
|
||
|
|
||
|
Used for Objective-C class types bridged to Swift value types. An empty
|
||
|
string ("") means a type is not bridged. Not supported outside of Apple
|
||
|
frameworks (the Swift side of it requires conforming to implementation-detail
|
||
|
protocols that are subject to change).
|
||
|
|
||
|
::
|
||
|
|
||
|
- Name: NSIndexSet
|
||
|
SwiftBridge: IndexSet
|
||
|
|
||
|
:DesignatedInit:
|
||
|
|
||
|
Used for init methods. Equivalent to ``NS_DESIGNATED_INITIALIZER``.
|
||
|
|
||
|
::
|
||
|
|
||
|
- Selector: "initWithFrame:"
|
||
|
MethodKind: Instance
|
||
|
DesignatedInit: true
|