An operator is a special symbol or phrase that you use to check, change, or combine values. For example, the addition operator (+
) adds two numbers, as in let i = 1 + 2
.
Swift supports most standard C operators and improves several capabilities to eliminate common coding errors. Like, the assignment operator (=
) doesn’t return a value, to prevent it from being mistakenly used when the equal to operator (==
) is intended. The tables below list the operators declared in Swift.
Table 1 - Prefix operators
Operator | Description |
---|---|
! | Logical NOT |
~ | Bitwise NOT |
+ | Unary plus |
- | Unary minus |
..< | Half-open range |
... | Closed range |
Table 2 - Postfix operators
Operator | Description |
---|---|
... | Closed Range |
Table 3 - Infix operators
The infix operators are grouped below by precedence group in decreasing order of precedence.
Operator | Description | Associativity | Precedence group |
---|---|---|---|
<< | Bitwise left shift | None | BitwiseShiftPrecedence |
>> | Bitwise right shift | None | BitwiseShiftPrecedence |
+ | Add | Left associative | AdditionPrecedence |
- | Subtract | Left associative | AdditionPrecedence |
* | Multiply | Left associative | MultiplicationPrecedence |
/ | Divide | Left associative | MultiplicationPrecedence |
% | Remainder | Left associative | MultiplicationPrecedence |
&+ | Add with overflow | Left associative | AdditionPrecedence |
&- | Subtract with overflow | Left associative | AdditionPrecedence |
&* | Multiply with overflow | Left associative | MultiplicationPrecedence |
& | Bitwise AND | Left associative | MultiplicationPrecedence |
| | Bitwise OR | Left associative | AdditionPrecedence |
^ | Bitwise XOR | Left associative | AdditionPrecedence |
..< | Half-open range | None | RangeFormationPrecedence |
... | Closed range | None | RangeFormationPrecedence |
is | Type check | Left associative | CastingPrecedence |
as, as?, and as! | Type cast | Left associative | CastingPrecedence |
?? | Nil coalescing | Right associative | NilCoalescingPrecedence |
?: | Ternary conditional | Right associative | TernaryPrecedence |
< | Less than | None | ComparisonPrecedence |
<= | Less than or equal | None | ComparisonPrecedence |
> | Greater than | None | ComparisonPrecedence |
>= | Greater than or equal | None | ComparisonPrecedence |
= = | Equal | None | ComparisonPrecedence |
!= | Not equal | None | ComparisonPrecedence |
= = = | Identical | None | ComparisonPrecedence |
!= = = | Not identical | None | ComparisonPrecedence |
~= | Pattern match | None | ComparisonPrecedence |
&& | Logical AND | Left associative | LogicalConjunctionPrecedence |
|| | Logical OR | Left associative | LogicalConjunctionPrecedence |
= | Assign | Right associative | AssignmentPrecedence |
*= | Multiply and assign | Right associative | AssignmentPrecedence |
/= | Divide and assign | Right associative | AssignmentPrecedence |
%= | Remainder and assign | Right associative | AssignmentPrecedence |
+= | Add and assign | Right associative | AssignmentPrecedence |
-= | Subtract and assign | Right associative | AssignmentPrecedence |
<<= | Left bit shift and assign | Right associative | AssignmentPrecedence |
>>= | Right bit shift and assign | Right associative | AssignmentPrecedence |
&= | Bitwise AND and assign | Right associative | AssignmentPrecedence |
|= | Bitwise OR and assign | Right associative | AssignmentPrecedence |
^= | Bitwise OR and assign | Right associative | AssignmentPrecedence |
1. Prefix operators
1.1 Logical NOT (!)
The logical NOT operator (!) inverts a Boolean value so that true
becomes false
, and false
becomes true
.
let allowedEntry = false
if !allowedEntry {
print("ACCESS DENIED")
}
//prints "ACCESS DENIED"
1.2 Bitwise NOT (~)
The bitwise NOT operator (~) inverts all bits in a number.
let initialBits: UInt8 = 0b00001111
let invertedBits = ~initialBits // equals 11110000
print(invertedBits)
//prints "240"
1.3 Unary plus (+)
The unary plus operator (+) simply returns the value it operates on, without any change.
let minusSix = -6
let alsoMinusSix = +minusSix
print(alsoMinusSix)
//prints "-6"
Although the unary plus operator doesn’t actually do anything, we can use it to provide symmetry in your code for positive numbers when also using the unary minus operator for negative numbers.
1.4 Unary minus (-)
The sign of a numeric value can be toggled using a prefixed -, known as the unary minus operator.
let three = 3
let minusThree = -three
print(minusThree)
//prints "-3"
let plusThree = -minusThree
print(plusThree)
//prints "3"
1.5 Half-open range (..<)
The half-open range operator (a ..< b) defines a range that runs from a to b, but doesn’t include b. The half-open range operator also has a one-sided form that’s written with only its final value.
let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names[..<2] {
print(name)
}
/* prints -
Anna
Alex */
1.6 Closed range (...)
The closed range operator (a...b) defines a range that runs from a to b, and includes the values a and b. The value of a must not be greater than b. The closed range operator has an alternative form for ranges that continue as far as possible in one direction
for name in names[...2] {
print(name)
}
/* prints -
Anna
Alex
Brian
*/
2. Postfix operators
2.1 Closed range (...)
For definition refer 1.6 Closed range
for name in names[2...] {
print(name)
}
/* prints -
Brian
Jack
*/
3. Infix operators
3.1 Bitwise left shift (<<)
The bitwise left shift operator (<<) move all bits in a number to the left by a certain number of places, according to the rules defined below.
- Bitwise left shifts have the effect of multiplying an integer by a factor of two.
let shiftBits: UInt8 = 4 // 00000100 in binary
shiftBits << 1 // 00001000
shiftBits << 2 // 00010000
shiftBits << 5 // 10000000
shiftBits << 6 // 00000000
3.2 Bitwise right shift (>>)
The bitwise right shift operator (>>) move all bits in a number to the right by a certain number of places, according to the rules defined below.
- Bitwise right shifts have the effect of dividing an integer by a factor of two.
let shiftBits: UInt8 = 4 // 00000100 in binary
shiftBits >> 1 // 00000010
shiftBits >> 2 // 00000001
shiftBits >> 3 // 00000000
3.3 Add (+)
Add operator computes addition.
let num1 = 10
let num2 = 2
let addition = num1 + num2
print(addition)
//prints "12"
3.4 Subtract (-)
Subtract operator computes subtraction.
let num1 = 10
let num2 = 2
let subtraction = num1 - num2
print(subtraction)
//prints "8"
3.5 Multiply (*)
Multiply operator computes multiplication.
let num1 = 10
let num2 = 2
let multiplication = num1 * num2
print(multiplication)
//prints "20"
3.6 Divide (/)
Divide operator computes division.
let num1 = 10
let num2 = 2
let division = num1 / num2
print(division)
//prints "5"
3.7 Remainder (%)
Remainder operator computes remainder after division.
let num1 = 10
let num2 = 2
let remainder = num1 % num2
print(remainder)
//prints "0"
3.8 Add with overflow (&+)
Overflow Add operator computes addition. Addition result can overflow in both the positive and negative direction.
Arithmetic operators (+
, -
, *
, /
, %
and so forth) detect and disallow value overflow, to avoid unexpected results when working with numbers that become larger or smaller than the allowed value range of the type that stores them.
For example, the Int16
integer type can hold any signed integer between -32768 and 32767. Trying to set an Int16
constant or variable to a number outside of this range causes an error:
var potentialOverflow = Int16.max
potentialOverflow = potentialOverflow + 1 // this causes an error
Here’s an example of what happens when an Int16
is allowed to overflow, using the overflow add operator (&+):
var int16Overflow = Int16.max
int16Overflow = int16Overflow &+ 1
print(int16Overflow)
//prints "-32768"
3.9 Subtract with overflow (&-)
Overflow Subtract operator computes subtraction. Subtraction result can overflow in both the positive and negative direction. Here’s an example of what happens when an Int16
is allowed to overflow, using the overflow subtract operator (&-):
var int16Overflow = Int16.min // -32768
int16Overflow = int16Overflow &- 1
print(int16Overflow)
//prints "32767"
3.10 Multiply with overflow (&*)
Overflow Multiply operator computes multiplication. Multiplication result can overflow in both the positive and negative direction. Here’s an example of what happens when an Int16
is allowed to overflow, using the overflow multiply operator (&*):
var int16Overflow = Int16.max
int16Overflow = int16Overflow &* 2
print(int16Overflow)
//prints "-2"
3.11 Bitwise AND (&)
The bitwise AND operator (&) combines the bits of two numbers. It returns a new number whose bits are set to 1 only if the bits were equal to 1 in both input numbers:
let firstSixBits: UInt8 = 0b11111100
let lastSixBits: UInt8 = 0b00111111
let middleFourBits = firstSixBits & lastSixBits
print(middleFourBits)
//prints "60"
//60 = 00111100 in binary
3.12 Bitwise OR (|)
The bitwise OR operator (|) compares the bits of two numbers. The operator returns a new number whose bits are set to 1 if the bits are equal to 1 in either input number:
let someBits: UInt8 = 0b10110010
let moreBits: UInt8 = 0b01011110
let combinedbits = someBits | moreBits
print(combinedbits)
//prints "254"
//254 = 11111110 in binary
3.13 Bitwise XOR (^)
The bitwise XOR operator, or “exclusive OR operator” (^), compares the bits of two numbers. The operator returns a new number whose bits are set to 1 where the input bits are different and are set to 0 where the input bits are the same:
let firstBits: UInt8 = 0b00010100
let otherBits: UInt8 = 0b00000101
let outputBits = firstBits ^ otherBits
print(outputBits)
//prints "17"
//17 = 00010001
3.14 Half-open range (..<)
For definition refer 1.5 Half-open range
Half-open ranges are particularly useful when you work with zero-based lists such as arrays, where it’s useful to count up to (but not including) the length of the list
let names = ["Anna", "Alex", "Brian", "Jack"]
let count = names.count
for i in 0..<count {
print("Person \(i + 1) is called \(names[i])")
}
//prints -
/*
Person 1 is called Anna
Person 2 is called Alex
Person 3 is called Brian
Person 4 is called Jack
*/
3.15 Closed range (...)
For definition refer 1.6 Closed range
The closed range operator is useful when iterating over a range in which you want all of the values to be used, such as with a for-in
loop:
for index in 1...5 {
print("\(index) times 5 is \(index * 5)")
}
//prints-
/*
1 times 5 is 5
2 times 5 is 10
3 times 5 is 15
4 times 5 is 20
5 times 5 is 25
*/
3.16 Type check (is)
We use type check operator (is
) to check whether an instance is of a certain subclass type. The type check operator returns true if the instance is of that subclass type and false if it is not.
let number = 1
let isNumberInt = number is Int
let isNumberFloat = number is Float
print(isNumberInt) //prints "true"
print(isNumberFloat) //prints "false"
3.17 Type cast (as, as?, and as!)
A constant or variable of a certain class type may actually refer to an instance of a subclass behind the scenes. Where you believe this is the case, you can try to downcast to the subclass type with a type cast operator (as?
or as!
).
Because downcasting can fail, the type cast operator comes in two different forms. The conditional form, as?
, returns an optional value of the type you are trying to downcast to. The forced form, as!
, attempts the downcast and force-unwraps the result as a single compound action.
as? - Use the conditional form of the type cast operator (as?) when you are not sure if the downcast will succeed. This form of the operator will always return an optional value, and the value will be nil if the downcast was not possible. This enables you to check for a successful downcast.
let randomObjectsArray: [Any] = [1, 1.2, "Hello", true, [1, 2, 3], "World!"]
for object in randomObjectsArray {
if let stringObject = object as? String {
print(stringObject)
}
}
as! - Use the forced form of the type cast operator (as!) only when you are sure that the downcast will always succeed. This form of the operator will trigger a runtime error if you try to downcast to an incorrect class type.
let randomIntArray: [Any] = [1, 2, 3, 4, 5]
for object in randomIntArray {
let intObject = object as! Int
print(intObject)
}
3.18 Nil coalescing (??)
The nil-coalescing operator (a ?? b
) unwraps an optional a
if it contains a value, or returns a default value b
if a
is nil
. The expression a is always of an optional type. The expression b
must match the type that is stored inside a
.
let defaultColorName = "red"
var userDefinedColorName: String? // defaults to nil
var colorNameToUse = userDefinedColorName ?? defaultColorName
print(colorNameToUse)
//prints "red"
// userDefinedColorName is nil, so colorNameToUse is set to the default of "red"
userDefinedColorName = "green"
colorNameToUse = userDefinedColorName ?? defaultColorName
print(colorNameToUse)
//prints "green"
// Now userDefinedColorName is "green", so colorNameToUse is set to the value of userDefinedColorName of "green"
3.19 Ternary conditional (?:)
The ternary conditional operator is a special operator with three parts, which takes the form question ? answer1 : answer2
. It’s a shortcut for evaluating one of two expressions based on whether question is true
or false
. If question is true, it evaluates answer1
and returns its value; otherwise, it evaluates answer2
and returns its value.
let contentHeight = 40
let hasHeader = true
let rowHeight = contentHeight + (hasHeader ? 50 : 20)
print(rowHeight)
//prints "90"
3.20 Less than (<)
Less than operator checks if the value of left operand is less than the value of right operand. If yes, then the condition becomes true.
let isOneLessThanTwo = 1 < 2
print(isOneLessThanTwo)
//prints "true"
3.21 Less than or equal (<=)
Less than or equal operator checks if the value of left operand is less than or equal to the value of right operand. If yes, then the condition becomes true.
let isOneLessThanOrEqualToOne = 1 <= 1
print(isOneLessThanOrEqualToOne)
//print "true"
3.22 Greater than (>)
Greater than operator checks if the value of left operand is greater than the value of right operand. If yes, then the condition becomes true.
let isOneGreaterThanTwo = (1 > 2)
print(isOneGreaterThanTwo)
//print "false"
3.23 Greater than or equal (>=)
Greater than or equal operator checks if the value of left operand is greater than or equal to the value of right operand. If yes, then the condition becomes true.
let isOneGreaterThanOrEqualToTwo = (1 >= 2)
print(isOneGreaterThanOrEqualToTwo)
//prints "false"
3.24 Equal (= =)
Equal operator checks if the values of two operands are equal or not. If yes, then the condition becomes true.
let isOneEqualToTwo = (1 == 2)
print(isOneEqualToTwo)
//prints "false"
3.25 Not equal (!=)
Not equal checks if the values of two operands are equal or not. If the values are not equal, then the condition becomes true.
let isOneNotEqualToTwo = (1 != 2)
print(isOneNotEqualToTwo)
//prints "true"
3.26 Identical (= = =)
Identical operator use to test whether two object references both refer to the same object instance.
let object1 = NSObject()
let object2 = NSObject()
let object3 = object1
let object1IsIdenticalToObject3 = (object1 === object3)
print(object1IsIdenticalToObject3)
3.27 Not identical (!==)
Not identical operator use to test whether two object references both do not refer to the same object instance.
let object1IsNotIdebticalToObject2 = (object1 !== object2)
print(object1IsNotIdebticalToObject2)
3.28 Pattern match (~=)
Pattern match operator use to pattern matching in a case statement. We can overload the ~=
operator to provide custom expression matching behaviour. Here is a simple example of defining a custom one and using it:
struct Person {
let name : String
}
// Function that should return true if value matches against pattern
func ~=(pattern: String, value: Person) -> Bool {
return value.name == pattern
}
let p = Person(name: "Vineet")
switch p {
case "Vineet":
print("Hey it's me!")
default:
print("Not me")
}
// prints "Hey it's me!"
if case "Vineet" = p {
print("It's still me!")
}
// prints "It's still me!"
3.29 Logical AND (&&)
The logical AND operator (a && b) creates logical expressions where both values must be true
for the overall expression to also be true
.
If either value is false
, the overall expression will also be false
. In fact, if the first value is false
, the second value won’t even be evaluated, because it can’t possibly make the overall expression equate to true
. This is known as short-circuit evaluation.
let enteredDoorCode = true
let passedRetinaScan = false
if enteredDoorCode && passedRetinaScan {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
//Prints "ACCESS DENIED"
3.30 Logical OR (||)
The logical OR operator (a || b) use to create logical expressions in which only one of the two values has to be true
for the overall expression to be true
.
Like the Logical AND operator above, the Logical OR operator uses short-circuit evaluation to consider its expressions. If the left side of a Logical OR expression is true
, the right side is not evaluated, because it can’t change the outcome of the overall expression.
let hasDoorKey = false
let knowsOverridePassword = true
if hasDoorKey || knowsOverridePassword {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// Prints "Welcome!"
3.31 Assign (=)
Simple assignment operator. Assigns values from right side operands to left side operand.
let b = 5
var a = 10
a = b
print(a)
//prints 5
3.32 Multiply and assign (*=)
Multiply and assignment operator. It multiplies the right operand with the left operand and assigns the result to the left operand.
let b = 5
var a = 10
a *= b
print(a)
//prints 50
3.33 Divide and assign (/=)
Divide and assignment operator. It divides the left operand with the right operand and assigns the result to the left operand.
let b = 5
var a = 10
a /= b
print(a)
//prints 2
3.34 Remainder and assign (%=)
Modulus and assignment operator. It takes modulus using two operands and assigns the result to the left operand.
let b = 5
var a = 10
a %= b
print(a)
//prints 0
3.35 Add and assign (+=)
Add and assignment operator. It adds the right operand to the left operand and assign the result to the left operand.
let b = 5
var a = 10
a += b
print(a)
//prints 15
3.36 Subtract and assign (-=)
Subtract and assignment operator. It subtracts the right operand from the left operand and assigns the result to the left operand.
let b = 5
var a = 10
a -= b
print(a)
//prints 5
3.37 Left bit shift and assign (<<=)
Left shift and assignment operator.
var shiftBitsAndAssign: UInt8 = 4 //00000100 in binary
shiftBitsAndAssign <<= 1 //00001000
shiftBitsAndAssign <<= 2 //00100000
3.38 Right bit shift and assign (>>=)
Right shift and assignment operator.
shiftBitsAndAssign >>= 1 //00010000
shiftBitsAndAssign >>= 2 //00000100
3.39 Bitwise AND and assign (&=)
Bitwise AND assignment operator.
var num1Bits: UInt8 = 0b11111100
let num2Bits: UInt8 = 0b00111111
num1Bits &= num2Bits
print(num1Bits)
//prints "60"
//60 = 00111100 in binary
3.40 Bitwise OR and assign (|=)
Bitwise exclusive OR and assignment operator.
var num1Bits: UInt8 = 0b11111100
let num2Bits: UInt8 = 0b00111111
num1Bits &= num2Bits
print(num1Bits)
//prints "255"
//255 = 11111111 in binary
3.41 Bitwise OR and assign (^=)
Bitwise inclusive OR and assignment operator.
var num1Bits: UInt8 = 0b11111100
let num2Bits: UInt8 = 0b00111111
num1Bits &= num2Bits
print(num1Bits)
//prints "195"
//195 = 11000011 in binary