As a language that can be called with Objective-C, Swift also has some types and features with C language. If your code needs it, Swift also provides a programming method that mixes programming with common C code structures.
Basic data types
Swift provides some basic data types of Swift that are equivalent to C language such as char, int, float, and double. However, these core primitive types of Swift cannot be implicitly converted to each other, such as Int. So only your code explicitly requires them to use these types again, and Int can be used whenever you want to use it.
Type C | Swift Type |
---|---|
bool | CBool |
char, signed char | CChar |
unsigned char | CUnsignedChar |
short | CShort |
unsigned short | CUnsignedShort |
int | CInt |
unsigned int | CUnsignedInt |
long | CLong |
unsigned long | CUnsignedLong |
long long | CLongLong |
unsigned long long | CUnsignedLongLong |
wchar_t | CWideChar |
char16_t | CChar16 |
char32_t | CChar32 |
float | CFloat |
double | CDouble |
enumerate
Swift introduces any C-style enumeration type marked with the macro NS_ENUM. This means that no matter whether the enum values are defined in the system framework or in custom code, their prefix names will be truncated when they are imported into Swift. For example, look at this Objective-C enum:
//Objective-C
typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
UITableViewCellStyleDefault,
UITableViewCellStyleValue1,
UITableViewCellStyleValue2,
UITableViewCellStyleSubtitle
};
In Swift, this is done:
//Swift
enum UITableViewCellStyle: Int {
case Default
case Value1
case Value2
case Subtitle
}
When you need to point to an enum value, use the enum name that starts with a dot (.):
//Swift
let cellStyle: UITableViewCellStyle = .Default
Swift also introduced the option marked NS_OPTIONS macro. While the behavior of options is similar to the introduced enumeration, options can also support some bit operations, such as &, | and ~. In Objective-C, you set the mark to zero (0) with an empty option. In Swift, using nil means there is no option.
pointer
Swift avoids giving you direct access to pointers as much as possible. However, when you need to manipulate memory directly, Swift also provides you with multiple pointer types. The following table uses Type as the placeholder type name to represent the syntax mapping.
For parameters, use the following mapping:
C Syntax | Swift Syntax |
---|---|
const void * | CConstVoidPointer |
void * | CMutableVoidPointer |
const Type * | CConstPointer<Type> |
Type * | CMutablePointer<Type> |
For multi-level pointers of return types, variables, and parameter types, use the following mappings:
C Syntax | Swift Syntax |
---|---|
void * | COpaquePointer |
Type * | UnsafePointer<Type> |
For class types, use the following mapping:
C Syntax | Swift Syntax |
---|---|
Type * const * | CConstPointer<Type> |
Type * __strong * | CMutablePointer<Type> |
Type ** | AutoreleasingUnsafePointer<Type> |
C Variable pointer
When a function is declared to accept the CMutablePointer<Type> parameter, the function can accept any of the following types as a parameter:
•nil, passed in as a null pointer
• A value of type CMutablePointer<Type>
• An operand is an input and output expression of the lvalue of type Type, which is passed in as the memory address of this lvalue
• An input-output Type[] value is passed as the starting pointer of an array, and its life cycle will be extended during this call
If you declare a function like this:
//Swift
func takesAMutablePointer(x: CMutablePointer<Float>) { /*...*/ }
Then you can call this function using any of the following ways:
//Swift
var x: Float = 0.0
var p: CMutablePointer<Float> = nil
var a: Float[] = [1.0, 2.0, 3.0]
takesAMutablePointer(nil)
takesAMutablePointer(p)
takesAMutablePointer(&x)
takesAMutablePointer(&a)
When a function is declared to use a CMutableVoidPointer parameter, the function accepts any Type operand of type similar to CMutablePointer<Type>.
If you define a function like this:
//Swift
func takesAMutableVoidPointer(x: CMutableVoidPointer) { /* ... */ }
Then you can call this function using any of the following ways:
var x: Float = 0.0, y: Int = 0
var p: CMutablePointer<Float> = nil, q: CMutablePointer<Int> = nil
var a: Float[] = [1.0, 2.0, 3.0], b: Int = [1, 2, 3]
takesAMutableVoidPointer(nil)
takesAMutableVoidPointer(p)
takesAMutableVoidPointer(q)
takesAMutableVoidPointer(&x)
takesAMutableVoidPointer(&y)
takesAMutableVoidPointer(&a)
takesAMutableVoidPointer(&b)
C always pointer
When a function is declared to accept the CConstPointer<Type> parameter, the function can accept any of the following types as a parameter:
•nil, passed in as a null pointer
•A CMutablePointer<Type>, CMutableVoidPointer, CConstPointer<Type>, CConstVoidPointer, or convert to CConstPointer<Type> AutoreleasingUnsafePointer<Type> value if necessary
• An operand is an input and output expression of the lvalue of type Type, which is passed in as the memory address of this lvalue
•A Type[] array value is passed as the starting pointer of an array, and its life cycle will be extended during this call
//Swift
func takesAConstPointer(x: CConstPointer<Float>) { /*...*/ }
Then you can call this function using any of the following ways:
//Swift
var x: Float = 0.0
var p: CConstPointer<Float> = nil
takesAConstPointer(nil)
takesAConstPointer(p)
takesAConstPointer(&x)
takesAConstPointer([1.0, 2.0, 3.0])
When a function is declared to use a CConstVoidPointer parameter, the function accepts any Type operand of type similar to CConstPointer<Type>.  If you define a function like this:
//Swift 
func takesAConstVoidPointer(x: CConstVoidPointer) { /* ... */ }
Then you can call this function using any of the following ways:
//Swift
var x: Float = 0.0, y: Int = 0
var p: CConstPointer<Float> = nil, q: CConstPointer<Int> = nil
takesAConstVoidPointer(nil)
takesAConstVoidPointer(p)
takesAConstVoidPointer(q)
takesAConstVoidPointer(&x)
takesAConstVoidPointer(&y)
takesAConstVoidPointer([1.0, 2.0, 3.0])
takesAConstVoidPointer([1, 2, 3])
Automatically release unsafe pointer
When a function is declared to accept the AutoreleasingUnsafePointer<Type> parameter, this function can accept any of the following types as a parameter:
•nil, passed in as a null pointer
•A AutoreleasingUnsafePointer<Type> value
• Its operand is original, copied to a temporary input and output expression of a buffer without an owner, the address of the buffer is passed to the call, and when returned, the value in the buffer is loaded, saved, and reassigned to the operand.
Note: This list does not contain an array.
If you define a function like this:
//Swift
func takesAnAutoreleasingPointer(x: AutoreleasingUnsafePointer<NSDate?>) { /* ... */ }
Then you can call this function using any of the following ways:
//Swift
var x: NSDate? = nil
var p: AutoreleasingUnsafePointer<NSDate?> = nil

takesAnAutoreleasingPointer(nil)
takesAnAutoreleasingPointer(p)
takesAnAutoreleasingPointer(&x)
Note: C function pointers have not been introduced by Swift.
Global constants
Global constants defined in C and Objective-C language source files are automatically introduced by Swift compile and used as global constants for Swift.
Preprocessing instructions
The Swift compiler does not include a preprocessor. Instead, it takes full advantage of compile-time properties, generation configurations, and language features to accomplish the same functionality. Therefore, Swift does not introduce preprocessing instructions.
Simple macro
In C and Objective-C, you usually use a macro constant defined by the #define directive, and in Swift, you can use global constants instead. For example: a global definition #define FADE_ANIMATION_DURATION 0.35 can be used to better express it in Swift. Since simple macros used to define constants are mapped directly into Swift global quantities, the Swift compiler will automatically introduce simple macros defined in C or Objective-C source files.
Complex macros
Complex macros used in C and Objective-C do not have a corresponding definition in Swift. Complex macros are macros that are not used to define constants, but to define macros that contain parentheses (), functions. Your use of complex macros in C and Objective-C is used to avoid type checking limitations and duplicate labor of the same code. However, macros can also cause bugs and refactoring difficulties. In Swift you can directly use functions and generics to achieve the same effect. Therefore, complex macros defined in C and Objective-C source files cannot be used in Swift.
Compile configuration
Swift code and Objective-C code are conditionally compiled in different ways. Swift code can be compiled conditionally based on the evaluation of the generated configuration. The generated configuration includes true and false literals, command line flags, and platform test functions in the following table. You can specify the command line flag using -D <#Flag#>.
function | Valid parameters |
---|---|
os() | OSX, iOS |
arch() | x86_64, arm, arm64, i386 |
Note: The build configuration of arch(arm) does not return true for 64-bit arm devices, and the build configuration of arch(i386) returns true when the code is running on a 32-bit iOS simulator.
A simple conditional compilation requires the following code format:
#if build configuration
statements
#else
statements
#endif
A statement declared by zero or more valid Swift statements, which can include expressions, statements, and control flow statements. You can add additional build configuration requirements, conditional compilation instructions with && and | | operators as well! Operator, add conditional control blocks with #elseif:
#if build configuration && !build configuration
statements
#elseif build configuration
statements
#else
statements
#endif
Contrary to conditional compilation of C compilers, Swift conditional compilation statements must be completely self-contained and syntactical-effective code blocks. This is because Swift code must be syntax checked even if it is not compiled.