Small knowledge, big challenge! This paper is participating in theEssentials for programmers”Creative activities

Abstract

IOS development, especially the conversion from OC to Swift, requires a new understanding of Array, what attributes Swift retains, what attributes are added, and what memory storage is, etc. After understanding these, the use of Array can be more in line with the thoughts of Swift and convenient for myself.

Array is one of the most common data types in an application, and you can use Array to process data in an application. Use the Array type to hold elements of a single type. Arrays can hold elements of any type — from Int to String, even Class — but the elements in an array must be of the same type.

Swift can create arrays using array literals. If the element type is not defined, Swift will automatically infer the type of the element in the array. Such as:

// Let numbers = [1, 2, 3] // Let names = ["li", "zhang"]Copy the code

You can also create an empty array by specifying the element type of the array in the declaration, for example:

Var emptyInt: [Int] = [] var emptyDouble: Array<Double> = Array()Copy the code

If you need a fixed number of defaults to initialize an Array, you can use Array(repeating: Count 🙂 to create:

var digitCounts = Array(repeating: 1, count: 3)
print(digitCounts)
// Prints "[1, 1, 1]"
Copy the code

Accessing an array element

When you need to perform operations on all elements of an array, you can use for-in to loop through the contents of the array.

for name in names {
  print(name)
}
// Print "li"
// Print "zhang"
Copy the code

You can use the isEmpty property to quickly check if the array contains any elements, which is the same as using the count property to find the number of elements in the array and determine if it is zero.

print(numbers.isEmpty) // Print false
print(numbers.count == 0) // Print false
Copy the code

The first and last attributes are used to safely access the first and last elements of an array, returning nil if the array is empty.

print(number.first) // Print "1"
print(number.last) // Print "3"
​
print(emptyInt.first, emptyInt.last, separator: ", ")
// Prints "nil, nil"
Copy the code

Individual elements in an array can be accessed by subscript. The first element of a non-empty array has subscript 0, and the array’s subscript ranges from 0 to count (excluding count). Values that use negative numbers, equal to, or greater than count raise runtime errors, such as:

print(number[0], number[2], separator: ", ")
// Prints "1, 3"
​
print(emptyInt[0])
// Triggers runtime error: Index out of range
Copy the code

Add and remove elements

Let’s say you need to store a list of incoming employees. During this time, you need to add and remove names.

var staffs = ["zhang", "wang", "li"]
Copy the code

Use the append(_:) method to add a single element to the end of the array. Append (contentsOf:) allows you to add multiple elements at the same time. The argument can be another array or a sequence of elements of the same type.

staffs.append("zhao")
staffs.append(contentsOf: ["song", "suo"])
// ["zhang", "wang", "li", "zhao", "song", "suo"]
Copy the code

You can also add new elements to the middle of an array, using insert(_:at:) to insert a single element, and insert(contentsOf:at:) to insert multiple elements from another collection or array literal. Elements at and after the index are moved back to make room.

staffs.insert("ding", at: 3)
// ["zhang", "wang", "li", "ding", "zhao", "song", "suo"] 
Copy the code

To remove elements from an array, use the remove(at:), removeSubrange(_:), and removeLast() functions.

staffs.remove(at: 0)
// ["wang", "li", "ding", "zhao", "song", "suo"] 
​
staffs.removeLast()
// ["wang", "li", "ding", "zhao", "song"] 
Copy the code

The effect of replacing an existing element with a new value is achieved by assigning a new value to a subscript.

if let i = staffs.firstIndex(of: "ding") {
  staffs[i] = "bian"
}
// ["wang", "li", "bian", "zhao", "song"]  
Copy the code

Increase the size of an array (important)

Each array retains a specific amount of memory to hold its contents. When you add elements to an array that exceed its reserved capacity, the array allocates more memory and assigns all of its elements to the new storage space. The time to add an element is fixed, and the performance is relatively average. But there are performance costs to reallocating operations, which occur less and less frequently as the array grows larger.

If you know approximately how many elements you need to store, use the reserveCapacity(_:) function before adding elements to avoid intermediate reallocation. Use the count and capacity attributes to determine how many more elements an array can hold without allocating more storage.

var array = [1, 2]
array.reserveCapacity(20)
Copy the code

For most Arrays of Element type, the storage area is a contiguous memory. For arrays of Element type class or ObjC Protocol, the storage area can be a contiguous memory, or an instance of NSArray. Since any subclass of NSArray can be an Array, there is no guarantee that it is a block of memory or an instance of NSArray in this case.

Modifying an array copy (emphasis)

Each array has a separate storage space for the values of all the elements contained in the array. For simple types, such as integers or other structures, when you change a value in an array, the value of that element does not change in any copy of the array. Such as:

var numbers = [4, 5, 6]
var numbersCopy = numbers
​
numbers[0] = 9
print(numbers)
// Prints "[9, 5, 6]"
print(numbersCopy)
// Prints "[4, 5, 6]"
Copy the code

If the elements of the array are instances of classes. In this case, a value stored in an array refers to an object that exists outside the array. If you change a reference to an object in an array, only that array has a reference to the new object. However, if two arrays contain references to the same object, you can see changes to the object’s properties in both arrays, for example:

class InterR {
  var value = 10
}
​
var integers1 = [InterR(), InterR()]
var integers2 = integers1
​
integers1[0].value = 100
print(integers2[0].value)
// Prints "100"
​
integers1[0] = InterR()
print(integers1[0].value)
// Prints "10"
print(integers2[0].value)
// Prints "100"
Copy the code

Like all variable-size collections in the standard library, arrays are optimized using copy-on-write. Multiple copies share the same storage space until one copy is modified. When this happens, the array being modified is stored in a new storage space and then modified in the corresponding location. Copy-on-write optimization can reduce the number of copies.

This means that if an array shares storage space with other copies, the first change to the array incurs the cost of copying the array. You can then operate on it as its sole owner.

In the following example, you create an array and two copies that share the same storage. When the original array is modified, it makes a unique copy of its storage before modifying it. Then modify it. The two copies continue to share the original storage space.

var numbers = [7, 8, 9] var copy1 = numbers var copy2 = numbers numbers[0] = 100 numbers[1] = 200 numbers[2] = 300 // numbers: [100, 200, 300] // Copy 1 and copy 2: [7, 8, 9]Copy the code

Switching between Array and NSArray (emphasis)

When accessing the API of an NSArray instance, use the type conversion operator AS to convert the Array instance. For conversion to succeed, the Element type of the array must be a class type, an @objc Protocol, or a link to Foundation type.

The following example shows how to connect an Array instance to NSArray using the write(to:atomically:) function. In this example, the Colors array can be converted to NSArray because the colors array’s String elements are converted to NSString. On the other hand, the compiler prevents converting the moreColors array because its Element type is Optional and it cannot convert Foundation.

let colors = ["periwinkle", "rose", "moss"] let moreColors: [String?]  = ["ochre", "pine"] let url = URL(fileURLWithPath: "names.plist") (colors as NSArray).write(to: url, atomically: true) // true (moreColors as NSArray).write(to: url, atomically: true) // error: cannot convert value of type '[String?] ' to type 'NSArray'Copy the code

If the Array’s elements are already instances of class or @objc Protocol, then the conversion from Array to NSArray takes only O(1) time and space; otherwise, it takes O(n) time and space.

When the element type of the target Array is a class or @objc protocol, the conversion from NSArray to Array first calls copy(with:) on the Array to get an immutable copy, Additional Swift bookkeeping work is then performed, which takes O(1) time. For already immutable instances of NSArray, copy(with:) usually returns the same array in O(1) time; otherwise, copy performance is uncertain. If copy(with:) returns the same Array, the NSArray and Array instances use the same copy-on-write optimization for the shared storage space, and the same optimization is used when two Array instances share the storage space.

When the element type of the target Array is a non-class type of the conversion Foundation type, the conversion from NSArray to Array copies the conversion to contiguous storage in O(n) time. For example, converting from NSArray to Array performs such a copy. No further conversions are required when accessing elements of an Array instance.

Pay attention to

The ContiguousArray and ArraySlice types are not converted, and instances of these types always have a contiguous memory space as their storage.

digression

Time is short and what you said may not be comprehensive. If you have any problems during your review, please leave a message in the comment section and I will reply as soon as possible