В последнее время я играл с переменными и разобрался с некоторыми опциями, доступными для языка. На первый взгляд Swift кажется довольно простым и имеет сходство с другими языками, с которыми я работал. Однако, если копнуть глубже, у него есть несколько довольно уникальных характеристик, которые делают его интересным для программирования.

"Обычные" переменные, также известные как примитивы

Фундаментальные строительные блоки практически любого приложения включают в себя базовые первичные типы переменных. Swift начинает вас здесь и дает вам доступ к:

/* 
  String = Allows us to work with text.  ex: "It is beautiful outside"
  Int = Data type for working with whole numbers. Ex: 0, 5, 100
  Float = Data type for working with decimal type numbers ex: 1.5, 2.25
  Double = Similar to Float but used for larger decimal values
  Bool = Data type for working with True or False statements.
*/

Теперь, с учетом сказанного, есть несколько способов их создания. Некоторые важные вещи, на которые следует обратить внимание в приведенном ниже примере.

  1. Разница между let и var
  2. Строго типизированные экземпляры с использованием :
// let = a keyword we use when we expect this value to be constant and not change.
let myVariable: String = "This string is constant"

// var = a keyword indicating that the value is variable and is expected to / can change.
var myVariable: String = "Hello Joseph!"

// Can declare multiples of the same type in a row
var hasWater, hasPicnicTables, hasShade : Bool

// Can even define starting values for multiples
let firstPeriod = 1, secondPeriod = 2, thirdPeriod = 3

Примечание. Возможно, вы заметили, что в последнем примере переменной не было идентификатора типа. Что ж, компилятор Swift автоматически определит тип для вас, если он не определен.

Swift включает в себя очень классную функциональность с его примитивными типами!

//Strings can have different cases to them
myStringVariable.uppercased() //"HELLO WORLD"
myStringVariable.lowercased() //"hello world"
myStringVariable.capitalized // "Hello World"

//Strings can use the .isEmpty to determine if the string is empty or not
if(myStringVariable.isEmpty){
  ...
}

//Bools can use the .toggle() option to automatically switch it to the opposite value
Button("Click me"){
  isActive.toggle()
}

//.description is used to give you a representation of the current value
Text(myVariable.description)

//You can also see a value of a variable by using it in a string
Text("This is the value of my variable: \(myVariable)")

Не совсем обычные типы переменных

Одной из величайших особенностей переменной является ее гибкость. Они могут быть буквально кем угодно! От цвета до пользовательского объекта. Хотя, я думаю, в какой-то момент большинство людей больше не считают их переменными, но все они имеют одно и то же базовое определение и по-прежнему сохраняются для последующего использования.

//Setting a constant background color variable
let backgroundColor : Color = Color.red

//A Tuple is a unique type that can store a group of values into one variable
let runningBack = (20, "Barry Sanders")

//Collections such as arrays
var fruitAssortment : [String] = ["Apples", "Oranges", "Plums"]

//Even entire views can be tucked away
var myView : some View{
  Text("Hi, this is part of myView")
}

Необязательные переменные — вы ничего не сделаете!

Вышеприведенные примеры великолепны и все, но иногда переменные могут иметь или не иметь значение для них. Что тогда!? Давайте возьмем какое-то ожидаемое значение, например код безопасности кредитной карты, как часть процесса проверки. Мы можем использовать необязательный параметр как простой способ проверить, было ли сохранено это значение или нет.

//To define an optional put a question mark next to the type 
var securityCode : Int? = nil

//Then later on we can check if it has a value or not. If it's not nil, continue!
if(securityCode != nil){
  ...
}

Сравнения — использование операторов

Как и в приведенном выше примере, нам часто нужно сравнить значение переменной с чем-то для оценки. Для этого мы можем использовать несколько разных операторов!

// use the == symbol to compare if these objects are equal in value
if( myValue1 == myValue2 ){
  ...
}

// use the != symbol to compar if these objects are NOT equal in value
if( myValue1 != myValue2 ){
  ...
}

/* Mathmatical type operators
   > for greater than
   < for less than 
   >= greater than or equal to
   <= less than or equal to
*/
if( myInt1 > myInt2){
  ...
}

Примечание. Метод проверки == и != иногда может вызвать некоторые проблемы, если вы не будете осторожны. Распространенной ловушкой, в которую попадают люди, является сравнение строковых значений. Иногда полезно быть таким явным, но часто вам нужно убедиться, что вы сравниваете правильные случаи для большей точности (совет: используйте .lowercased() или .uppercased() для каждого значения для этой цели).

Сравнения — проверка типов по ключевому слову is

Но что, если нам нужно выяснить, к какому типу относится что-то? Возможно, это происходит, когда мы перебираем набор значений. Для этого примера предположим, что у нас есть коллекция объектов Car. Теперь мы хотим посмотреть, какие из них являются электромобилями (Tesla).

struct CarExample: View 
{
  //create our collection of cars
  let cars : [Car] = [Tesla(), Ford(), Ford(), Tesla(), Tesla()]

  var body: some View 
  {
    VStack(alignment: .leading, spacing: 10)
    {
      //Iterate through our collection
      ForEach(cars){ car in

        //** Use the is keyword to check the type of the object!
        if car is Tesla{
          Text("This car is electric: \(car.isElectric.description)")
        }
        else{
          Text("This car is not electric: \(car.isElectric.description)")
        }
      }
    }
  }
}

//Basic car classes used for our example above
public class Car : Identifiable
{
  var isElectric : Bool
  init(electric : Bool){
    isElectric = electric
  }
}
public class Tesla : Car
{
  init(){
    super.init(electric: true)
  }
}
public class Ford : Car
{
  init(){
    super.init(electric: false)
  }
}

Преобразование типов

Этот язык типобезопасен, что означает, что он не позволит вам наделать глупостей, назначив какие-либо другие типы значений чему-либо, если оно уже определено как нечто другое. Таким образом, вы не сможете случайно установить значение Int в Bool. Однако бывают случаи, когда вам нужно преобразовать значение из одного в другое.

Хотя мы немного ранее коснулись того, как получить строковые значения из ваших переменных, у каждого класса также есть способ создать новый объект из заданного значения. Ниже у нас есть пара примеров. Первый показывает, что мы можем взять значение Double и преобразовать его в Int, по существу отбросив десятичные значения. Во втором примере мы создаем новый Bool из строки.

/* In the example below we don't actually care about the decimal places
   so we can convert from double to Int */
let myDoubleValue : Double = 2.5

Text("Showing an Int value: \( Int(myDoubleValue) )") //2
Text("Showing as a String: \( myDoubleValue ) ") //2.500000
Text("Showing as a String: \( myDoubleValue.description ) ") //2.5

/* Creating a bool object from a string value */
let myStringValue : String = "true"

Text("Showing text as a bool: \( Bool(myStringValue)!.description )")

ПРИМЕЧАНИЕ. В последнем примере вы заметите ! после нашего вызова Bool(). Это потому, что система не знает, может ли она создать логическое значение из данного значения, поэтому она возвращает необязательный (пару абзацев назад). ! просто распаковывает значение, так как мы знаем, что оно есть (не используйте !, если вы не уверены).

Оболочка @ State

Когда вашей переменной необходимо обновить состояние пользовательского интерфейса, вы можете использовать эту оболочку. По сути, он следит за любыми изменениями в переменной, а затем сигнализирует об обновлении пользовательского интерфейса при изменении. Обратите внимание, что это не работает с let, так как это константа, не ожидающая изменений!

//Since this displays in our UI, when the color is changed it will change the background
@State var backgroundColor = Color.red

var body: some View{
  ZStack
  {
    backgroundColor
      .edgesIgnoringSafeArea(.all)

    VStack{
      //When this button clicks it sets the value of our @State variable
      Button("Update Color"){
        backgroundColor = Color.purple
      }
    }
  }
}

Оболочка @ Binding

В большинстве языков программирования, с которыми я работал, всегда был какой-то способ передачи значений в том, что они называют способом по значению или по ссылке.

По значению = передается только значение, и любые его изменения НЕ влияют на исходный объект.

По ссылке = передается ссылка на исходный объект, и любые внесенные изменения повлияют на исходный объект.

По сути, оболочка привязки позволяет нам передавать переменную по ссылке!

Здесь мы берем предыдущий пример и перемещаем основные компоненты в новое дополнительное представление. Однако подвиду нужна ссылка на объект цвета, который он использует, чтобы кнопка могла обновить цвет фона.

  1. В нашем подчиненном представлении мы объявляем переменную, с которой нам нужно работать, используя оболочку @ Binding.
  2. При передаче переменной в инициализатор подпредставления с использованием $ для привязки переменной
struct ColorExample: View{
  @State var mainColor : Color = Color.red
  
  var body: some View{
    //Use the $ sign to bind this variable in the init of the sub view
    SubViewWithBackground(backgroundColor: $mainColor)
  }
}

struct SubViewWithBackground : View {
  
  @Binding var backgroundColor : Color

  var body: some View{
    ZStack
    {
      backgroundColor
        .edgesIgnoringSafeArea(.all)
  
      VStack{
        /* When this button clicks it sets the  value of our @State variable.
           Which is just a reference to our mainColor
         */
        Button("Update Color"){
          backgroundColor = Color.purple
        }
      }
    }
  }
}

Ну, это было совсем немного, чтобы покрыть! Сумасшедшая часть заключается в том, что это даже близко не все, что вы можете узнать по этой теме. Тем не менее, это чертовски хорошее начало. Это просто заметки и странные примеры мячей, которые я пытался придумать. Поиграйте с ним немного и привыкните к работе с ними. Это на самом деле довольно круто и очень гибко!

До следующего раза сохраняйте спокойствие и продолжайте кодить!