Write down the learning route of swift

This blog is used as a personal note. If there are any errors, please point them out. Thank you. The main record is the different syntax or concepts in java.

Character string

  1. Multiple line string literals in swift (literals can be interpreted as strings)
    Multiline string literal quantities begin or end with three double quotes.

  2. Use backslashes in multiline literals if you don't want to wrap lines

  3. Turning off blank strings before quotation marks'''indicates how many blank strings will be ignored

  4. Escape conceit is like any other voice
    \0 (empty character), \(backslash), \t (horizontal tab), \n (line break), \r (carriage return),'(double quotation mark), '(single quotation mark)

  5. String creates a new copy of an existing string during operation

  6. for-in
    for has been discarded in swift

  7. Glyph group
    let eAcute: Character = "\u{E9}" // é
    let combinedEAcute: Character ='u{65}u{301}'// e followed by ́
    // eAcute is eE, combinedEAcute is eE
    The first is a single swift Character value, which represents an expandable glyph group and is a single scalar. The second case is the glyph group of two scalars.
    Also review: swift defines a variable variable variable name: variable type = xxxx

  8. Strings are considered equal as long as the semantic information of the extensible glyph group is equal.
    However, it is important to note that characters with the same length in different languages have different semantics.
    let latinCapitalLetterA: Character = "\u{41}"

let cyrillicCapitalLetterA: Character = "\u{0410}"

if latinCapitalLetterA != cyrillicCapitalLetterA {
print("These two characters are not equivalent")
}
9. Glyph groups and conceit are different concepts. Glyph groups are made up of unicode scalars. The count function is used to count the number of characters.
10. String Index
String cannot directly access the character at its corresponding position through [number], so should be used. Index (predicate: index)
11. Substring SubString
The swift substring subString uses the String's memory space, which is useful for performance optimization.

Collection Type

Array,Sets,Dictionary
1. Array is about the same as java
2. Sets (single, out of order)
sets has the following additional logical operations:


3. Similar to map, no special api
keys and values can be manipulated separately

	let houseAnimals: Set = ["🐶", "🐱"]
	let farmAnimals: Set = ["🐮", "🐔", "🐑", "🐶", "🐱"]
	let cityAnimals: Set = ["🐦", "🐭"]
	
	houseAnimals.isSubset(of: farmAnimals)
	// true
	farmAnimals.isSuperset(of: houseAnimals)
	// true
	farmAnimals.isStrictSuperset(of: houseAnimals)
	// true strictly determines whether it is a parent set and is not equal
	farmAnimals.isDisjoint(with: cityAnimals)
	// true

control flow

  1. A tips independent of control flow:
    Unlike java in swift, objects can be referenced in print () with \ (variable name), similar to the & variable name in c
  2. for and java have different syntax:
    let minuteCount = 5
    for ticktok in 0...< minuteCount {
    print("should print (ticktok)")
    }
    Like if, you do not need to write a control condition in (), and when the minuteCount loop condition is of type int, you need to precede it with a number control like 0...
  3. while and java have different syntax:
    do... while in java became
    repeat {
    statements
    } while condition
    (which should be rarely used)
  4. switch:
    / No need to write break! Matching in swift will terminate automatically; If break is used, the switch's code block is skipped to execute the first line of code after the code.
    After a successful match, if you do not want to terminate, you want additional judgment and processing, using fallthrough:
let integerToDescribe = 5
var description = "The number \(integerToDescribe) is"
switch integerToDescribe {
case2, 3, 5, 7, 11, 13, 17, 19:
    description += " a prime number, and also"
    fallthrough
default:
    description += " an integer."
}
print(description)
// Output "The number 5 is a prime number, and also an integer."

At the same time, tuples can be used in conditions to make conditional judgments, such as:
Underline () matches all values

let somePoint = (1, 1)
switch somePoint {
case (0, 0):
    print("\(somePoint) is at the origin")
case (_, 0):
    print("\(somePoint) is on the x-axis")
case (0, _):
    print("\(somePoint) is on the y-axis")
case (-2...2, -2...2):
    print("\(somePoint) is inside the box")
default:
    print("\(somePoint) is outside of the box")
}

? Temporary variables can be used (variables are assigned automatically as placeholders)
where can be used to append criteria
. Multiple cases can be combined to use a composite case
5. Tuples are mentioned in the last note, so here are some concepts:
A tuple is a comma-separated set of values within parentheses (), where the value can have a name.
* Once declared, values can be changed, but elements cannot be added/deleted
* Cannot change declared element name
* Declared names can be omitted, but tuples of names cannot be declared, and names cannot be added:
Reference resources:

https://juejin.cn/post/6844903936630112269

  1. Conditional control can be labeled (can be understood as naming a conditional control)
  2. guard
    There must be else for conditional control of Yes-No scenarios
  3. Detecting API availability
if#available(iOS 10, macOS 10.12, *) {
    // Use iOS 10 API on iOS and macOS 10.12 API on macOS
} else{
    // API s using previous versions of iOS and macOS
}

Understand the role of this code. I don't know, but how do I use it, and what judgments did avaliable make? Where is the judgment api written? Google can use notes to check above:

https://www.hackingwithswift.com/new-syntax-swift-2-availability-checking

You can add **@available** to a class or method

enumeration

  1. Define or use let or var
  2. Different types of associated values can be stored
enum Barcode {
    case upc (Int, Int, Int, Int)
    case qrCode (String)
}
  1. Raw Value - The type specified while defining an enumeration is called Raw Value
enum ASCIIControlCharacter: Character {
    case tab = "\t"
    case lineFeed = "\n"
    case  carriageReturn = "\r"
}

If the original value is of type int, the original value of each enumeration member increases without specifying it

Structures and Classes

There are also structural and class differences in c++:
1. All resources can be released when a class is destructed
2. Classes have inheritance
3. Delivery is different, struct is value transfer, class is reference transfer, that is to say:
Structural a = Structural b, which actually copies B and passes it to a, guarantees security. So changes to a will not affect B.
But class a = b actually passes a reference to b to a, and a change is a change to a reference, and because b points to the same reference, the value of b changes.

function

  1. Definition of function
    The function definition in swift is unique. func is used to represent the function to be defined, the life name and type to be passed along, followed by **-> to specify the return type ** (you can not specify it if you don't have rice to come back). The name of the parameter is specified in the declaration when the function is called. (Correctly, the correct name for the parameter passed here should be the parameter label, no label specified, so the default is the parameter name)
func getSum(para1: Int, para2: Int) -> Int {
    return para1 + para2
}
//return 11

print(getSum(para1:5, para2:6))
  1. The return type can be a tuple
    You can use tuples as return values, and the members of tuples are named in the return type of the function. To view the corresponding tuple members, you can use them directly as return objects.
func minMax(array: [Int]) -> (min: Int, max: Int) {
    varcurrentMin = array[0]
    varcurrentMax = array[0]
    forvalue inarray[1..<array.count] {
        ifvalue < currentMin {
            currentMin = value
        } elseifvalue > currentMax {
            currentMax = value
        }
    }
    return(currentMin, currentMax)
}

let result= minMax(array: [5,6,7])
print(result.max, result.min)
  1. Return tuple optional type
    Is there one more code behind the return type? Symbols, which represent the type of rice returns, may or may not be nil, can be understood as the Optional wrapper class of java8.
func minMax(array: [Int]) -> (min: Int, max: Int)? {
    varcurrentMin = array[0]
    varcurrentMax = array[0]
    forvalue inarray[1..<array.count] {
        ifvalue < currentMin {
            currentMin = value
        } elseifvalue > currentMax {
            currentMax = value
        }
    }
    return(currentMin, currentMax)
}

At this point, even an empty object is passed in without error:

let result2= minMax(array:)

let result= minMax(array: [5,6,7])
print(result!.max)
  1. Value of optional type '(min: Int, max: Int)?' must be unwrapped to refer to member '
    After using code 3, this error occurred in the previous code, meaning that the variable for option type must be unpacked before it can point to a member. Is this because you are not familiar with swift? And! Caused by.
    In swift, yes? And! Two symbols, where? Symbols represent wrapping variables as optional,! Represents forced unpacking of the wrapper class (an error-null pointer exception if the internal value is nil), which must first be unpacked when using members of the option tuple. Using the code above as an example, another way to avoid errors is to make a non-empty judgment as follows:
if let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) {
    print("min is \(bounds.min) and max is \(bounds.max)")
}

if let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) {
    print("min is \(bounds.min)and max is \(bounds.max)")
}
// Print "min is-6 and Max is 109"
  1. When a function specifies a return type, it can be returned implicitly. (Like a lambda expression, you don't need to write return if you don't write {})

  2. Art of Passing on
    . You can add an argument label before a parameter, either without it or with _ To make it clear not to add
    You can give defaults when passing parameters, and override them if they have values (c++ or not clear in java)
    Passing variable parameters (as with js):

func arithmeticMean(_numbers: Double...) -> Double{
    vartotal: Double= 0
    fornumber innumbers {
        total += number
    }
    returntotal / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
// Returns 3.0, which is the average of these five numbers.
arithmeticMean(3, 8.25, 18.75)
// Returns 10.0, which is the average of the three numbers.

When you want to modify a parameter (the swift default parameter is a constant):
Similar to c++, use the &symbol when passing and the inout keyword before the parameter you want to change

func swapTwoInts(_a: inout Int, _b: inout Int) {
    lettemporaryA = a
    a = b
    b = temporaryA
}

var someInt3 = 3
var anotherInt107 = 107
swapTwoInts(&someInt3, &anotherInt107)
print("someInt3 is now \(someInt3), and anotherInt107 is now \(anotherInt107)")
// Print "someInt is now 107, and anotherInt is now 3"
The following code will fail,**Because it was not added inout Keyword, and argument is a constant by default**:
funcarithmeticMean(_numbers: Double...) -> Double{
    vartotal: Double= 0
    fornumber innumbers {
        total += number
    }
    returntotal / Double(numbers.count)
}
testConstant = 2
//Cannot assign to value: 'testConstant' is a 'let' constant
  1. Function Type (Functional Interface for java8?)
    Personal understanding: Function type, like other basic types, is a type and can be assigned as a variable, similar to the idea of java's functional interface: function expression is treated as a parameter. When the function type has the same input and output parameters, the function can be represented by a parameter. The following:
func addTwoInts(a:Int, b:Int) -> Int{
    a+b
}
func printHelloWorld() {
    print("hello world")
}

var myFunctional:(Int,Int) -> Int= addTwoInts(a:b:)
myFunctional(5,6)
var myFunctional2:()-> Void= printHelloWorld
myFunctional2()

functional1 indicates the presence and absence of arguments, and functional2 represents the function type parameter without arguments.
The function type can also be used as a parameter to a function.
8. Function type as return value

funcstepForward(_input: Int,_input2: Int) -> Int{
    returninput + input2 - 1
}
funcstepBackward(_input: Int, _input2: Int) -> Int{
    returninput + input2 - 1
}
func chooseStepFunction(backward: Bool) -> (Int, Int) -> Int {
    returnbackward ? stepBackward : stepForward
}
var currentValue1 = 3
var currentValue2 = 3
let moveToZero = chooseStepFunction(backward: currentValue1 > 0)
let testResultTmp = moveToZero(currentValue1, currentValue2) 
**//Output 5, moveToZero is a function type expression**

Closure expression

That is, anonymous functions

  1. General Form
    {(parameters) -> return type in
    statements
    }
    Introduced by keyword in
var testArrays: [Int] = [1,2,3,4,5]
var sortedTestArrays= testArrays.sorted(by: { (item1: Int, item2:Int) -> Boolin
    returnitem1 > item2
})
print(sortedTestArrays)

Because of type inference, the expression can be simplified to:

var sortedTestArrays2= testArrays.sorted(by: {item1, item2 initem1 > item2})

Inline closures provide parameter name abbreviations internally, so the expression can be further simplified to understand that both $0 and $1 can be interpreted as reference placeholders for the first and second parameters:

var sortedTestArrays3= testArrays.sorted(by: {$0 > $1})

There are built-in implementations in swift, even with one > symbol:

var sortedTestArrays4 = testArrays.sorted(by: >)
  1. Trailing closure
    When you need to pass a very long closure expression to a function as the last parameter, replace it with a trailing closure (you don't need to write parameter labels, just type {})
func someFunctionThatTakesAClosure(closure: () -> Void) {
    // Function body part
}

// The following is a function call without a trailing closure
someFunctionThatTakesAClosure(closure: {
    // Closure Body Part
})

// The following is a function call using a trailing closure
someFunctionThatTakesAClosure() {
    // Closure Body Part
}

Here's an example (map is the same as stream's map function, so why do you want to use number=number - to pass by value? You can modify the local variable number without affecting the original number. I think it's better to change the name to avoid ambiguity):

let digitNames = [
    0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",
    5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers= [16, 58, 510]

let  Strings= numbers.map{
    (number) -> String in
    var number = number
    var output = ""
    repeat{
        output = digitNames[number % 10]! + output
        number /= 10
    }while number > 0
    return output
}
//output: "OneSix" "FiveEight" "FiveOneZero"
  1. Value capture
    Closures can capture constants or variables in the context in which they are defined. Even if the original scope defining these constants and variables no longer exists. (Don't get it. Look back a little more)
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementer() -> Int{
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}

let incrementByTen= makeIncrementer(forIncrement: 10)
let testResult1 = incrementByTen()
print(testResult1)
  1. Closure is a reference type
    In the example above, incrementByTen itself is a constant, which is correct, but is set to a reference called a closure. (One of the concepts in C++, forget what it is)

  2. Escape Closure
    That is, ->Closure not executed in function scope

  3. Automatic closure (associate Supplier interface - > no parameters but return value)
    No parameters are accepted, returns the value of the expression wrapped in it, and the expression inside the closure will execute only when it is called. If the expression is not called, the expression inside the closure will never execute.
    Examples include the following:

// customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: () -> String) {
    print("Now serving \(customerProvider())!")
}
serve(customer: { customersInLine.remove(at: 0) } )
// Print out "Now serving Alex!"

In serve r (customer is the parameter label, customerProvider is the parameter name, accepts a closure of a function type)
The definition of a closure is that when you use func serve r, you define the customer closure.

// customersInLine i= ["Barry", "Daniella"]
var customerProviders: [() -> String] = []
func collectCustomerProviders(_customerProvider: @autoclosure@escaping() -> String) {
    customerProviders.append(customerProvider)
}
collectCustomerProviders(customersInLine.remove(at: 0))  

//What is the declaration of line 301 if it is a closure expression here? -> Line 301 is an array declaring an empty function type!

collectCustomerProviders(customersInLine.remove(at: 0))

print("Collected \(customerProviders.count) closures.")
// Print "Collected 2 closures."
forcustomerProvider incustomerProviders{
    print("Now serving \(customerProvider())!")
}
// Print "Now serving Barry!"
// Print "Now serving Daniella!"

This is an escape autoclosure, customerProviders is an empty array of function types, coolectCustomerProviders accepts an autoclosure as a function type. Each call to customerProviders places the closure expression in the customerProviders array.
Auto and escape closures are more like an idea than a single concept

attribute

  1. Delayed Load Storage Properties
    The Delayed Load property is initialized when calculation is required after instance construction is complete and must be a variable. (Because a constant attribute must have an initial value before construction is complete), the keyword is lazy, preceded by the attribute name.
class DataImporter {
    /*
    DataImporter Is a class responsible for importing data from an external file.
    Initialization of this class takes a lot of time.
    */
    var fileName = "data.txt"
    // Data import is provided here
}

class DataManager {
    lazyvarimporter= DataImporter()
    vardata: [String] = []
    // Data management capabilities are provided here
}

let manager= DataManager()
manager.data.append("Some data")
manager.data.append("Some more data")
// The importer property of the DataImporter instance has not been created yet

Lazy loading cannot be guaranteed to be created only once in a multithreaded situation.
2. Computing attributes
Calculated attributes are those that do not store values directly and set their values indirectly through getter s and setter s.

struct Point {
    var x= 0.0, y= 0.0
}
struct Size {
    var width= 0.0, height= 0.0
}
struct Rect {
    var origin= Point()
    var size= Size()
    var center: Point{
        get{
            let centerX = origin.x + (size.width/ 2)
            let centerY = origin.y + (size.height/ 2)
            return Point(x: centerX, y: centerY)
        }
        set(newCenter) {
            origin.x= newCenter.x - (size.width/ 2)
            origin.y= newCenter.y - (size.height/ 2)
        }
    }
}
varsquare= Rect(origin: Point(x: 0.0, y:0.0),
                  size: Size(width: 10.0, height: 10.0))
print("before----1 \(square.origin.x), \(square.origin.y)")
let initialSquareCenter = square.center  //getter used here
print(initialSquareCenter.x, initialSquareCenter.y)
print("before----2 \(square.origin.x), \(square.origin.y)")
square.center= Point(x: 15.0, y: 15.0) //setter used here
print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
// Print "square.origin is now at (10.0, 10.0)"

center is a computed property
You can simplify getters and setter s, which by default do not specify a new value for the entry name. Simplify the getter default return statement, similar to the implicit return of a function.

struct CompactRect {
    var origin= Point()
    var size= Size()
    var center: Point{
        get{
            Point(x: origin.x + (size.width/ 2),
                  y: origin.y + (size.height/ 2))
        }
        set{
            origin.x= newValue.x - (size.width/ 2)
            origin.y= newValue.y - (size.height/ 2)
        }
    }
}
  1. Attribute Watcher
    The observer responds each time an attribute changes. Acts on the following three attributes:
    Storage type
    . Inherited storage type
    The type of calculation inherited
    There are two observers, willSet (default newValue) and didSet (default oldValue), with oldValue using one thousand values as input by default.
class StepCounter {
    var totalSteps: Int= 0{
        willSet(newTotalSteps) {
            print("take totalSteps The value of is set to \(newTotalSteps)")
        }
        didSet{
            iftotalSteps > oldValue  {
                print("Added \(totalSteps - oldValue) step")
            }
        }
    }
}
let stepCounter= StepCounter()
stepCounter.totalSteps = 200
// Set the value of totalSteps to 200
// 200 steps added
stepCounter.totalSteps = 360
// Set the value of totalSteps to 360
// Add 160 steps
stepCounter.totalSteps = 896
// Set the value of totalSteps to 896
// Add 536 steps

In this example, totalSteps is set to an attribute observer, and both are set, so each time a change occurs, both observers are triggered.
4. Attribute wrapper

@propertyWrapper
struct TwelveOrLess {
    private var number = 0
    var wrappedValue: Int {
        get{ returnnumber}
        set{ number= min(newValue, 12) }
    }
}
struct SmallRectangle {
    @TwelveOrLess varheight: Int
    @TwelveOrLess varwidth: Int
}

varrectangle= SmallRectangle()
print(rectangle.height)
// Print "0"

rectangle.height = 10
print(rectangle.height)
// Print "10"

rectangle.height = 24
print(rectangle.height)
// Print "12"

Attribute wrappers need to define wrappedValue wrappers, where the value of number cannot be less than 12, and the wrapper should be used by annotations before the height s and width s attributes in smallrectangle.

Set the initial value of the property wrapper:

@propertyWrapper
struct SmallNumber {
    private var maximum: Int
    private var number: Int

    var wrappedValue: Int {
        get{ returnnumber}
        set{ number= min(newValue, maximum) }
    }

    init() {
        maximum= 12
        number= 0
    }
    init(wrappedValue: Int) {
        maximum= 12
        number= min(wrappedValue, maximum)
    }
    init(wrappedValue: Int, maximum: Int) {
        self.maximum= maximum
        number= min(wrappedValue, maximum)
    }
}

Three inits () are overloaded, and the initial value of the wrapper property calls which initialization constructor is needed based on the arguments.

  1. Type Properties
    The third property in switft, decorated with static, is accessed through a type stencil, not an instance.

Method

  1. selft is this in c++ and java
  2. Modify the properties of enumerations and structs
    Add the mutating keyword before the attributes so that they can be changed (remember vaguely that there is a variable constant mutable in c++? Keyword, how do you rename a lot of things in swift.)
  3. Method Kind
    Instance method: General method
    Type method: static modification

subscript

How can swift subscriptions be so cumbersome? In addition to indexing, swift can also customize read-only subscripts as follows:

  1. subscript keyword:

struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int{
returnmultiplier* index
}
}
letthreeTimesTable= TimesTable(multiplier: 3)
print("six times three is (threeTimesTable[6])")
//Print "six times three is 18"

  1. Type table below - > For Type
	enum Planet: Int {
	    case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
	    staticsubscript(n: Int) -> Planet {
	        returnPlanet(rawValue: n)!
	    }
	}
	let mars= Planet[4]
print(mars)

inherit

Unlike java:

  1. Inherited syntax is different, no keyword is required, just follow the class with a colon + parent name
    Example: class Bicycle: Vehicle {
    xxxx : xxx
    }
  2. Override must precede func with override keyword
  3. Property watchers can also be overridden
    Add final to prevent overrides

constructor

  1. The swift constructor name is called init()

  2. Specify Constructors and Convenient Constructors
    Convenient constructor:
    convenience init(para) {
    statement
    }
    * Specify that the constructor must always proxy up
    * Convenience constructors must always be proxied horizontally

  3. Security check
    The swift is constructed in two phases: the first phase assigns initial values to all storage attributes, and the second phase customizes storage attributes before instantiation
    1) The specified constructor must ensure that all storage properties of the class in which it resides must be initialized before the construction task can be given to the father's constructor
    2) Specify that the constructor must proxy the parent constructor up before setting a value for inherited attributes, otherwise it will set a value and the value before calling the parent constructor will be overridden
    3) Facility constructor invokes other constructors before assignment, otherwise its assignment is overridden
    4) No instance methods can be invoked until the first stage of construction is complete, and only after the first stage is completed will instances of classes be valid to access properties and methods.

  4. Failable constructor init?()
    Cannot have the same parameter name and type as other non-failable constructors
    What's the use? A construct failure returns a nil, and a construct failure would have resulted in an error?

  5. Required Constructor
    The constructor is preceded by the required keyword, which requires all subclasses to be implemented

  6. Setting default values for properties through closures or functions

class SomeClass {
    let someProperty: SomeType = {
        // Create a default value for someProperty in this closure
        // someValue must be the same as the SomeType type
        return someValue
    }()
}

You must add parentheses, which indicate that the return value will be assigned, or else you will assign a closure expression.
In addition, the construction of other properties of the closure has not been initialized, so other properties, including the self property, cannot be used.

Destruction

Define destructive behavior using the keyword deinit {
statement
}

Optional Chain Call

  1. An optional chain call is a way to request and invoke attributes, methods, and subscripts on an optional value whose current value may be nil.
  2. Multi-tier optional chain call
    An optional chain call returns if the accessed value is not optional
    If the accessed value is not optional, an optional chain call will not make the return value more optional (there will be no Optional < Optional > case for java8)

Tags: Java Back-end

Posted on Tue, 30 Nov 2021 13:37:35 -0500 by olivarespablo