Thursday, September 20, 2018

Swift 4 Introduction Series 1.16 - Basic of Structures

Basic of Structures

We can use structure to group all the variables and function under a single named entity. Before we worked on the app lets learn the basics syntax of Structure.


Define Structure

To define structure, use the syntax:


struct <name_of_structure> {


// Definition of Structure

}


Note: For name of structure, use capital letter for the first letter to represent data type


struct BasicContact {
   
}



What is Properties?

Properties in structure are constant and variables.


See example:


struct BasicContact {
   
   var name = String()
   var no  = Int()
   
}


Most of the time we need variables. However, sometimes we use constant to store fixed parameters.


For the example above, lets restrict the length of the name to 50 character


struct BasicContact {
   
   var name = String()
   var no  = Int()
   
   // Constant parameter
   let maxLengthName = 50
   
}



What is Instances?

The structure defined above describe how the structure "BasicContact" looks like. To create the working copy of the structure, we create an instances of the structure.


We use the syntax:


var/let <variable_name> = <structure_name>(<value_of_properties>)


Alternatively, we can use the following syntax if the variables are initialized


var <variable_name> = <structure_name>()


Example:


var list1 = BasicContact()
let list2 = BasicContact(name: "Thompson", no: 76238473)


Please note that if we create an instance with constant, we cannot change the values even if it is created as variable in the structure.


Instance Creation and Initialization

When we create a structure instance, all the properties define in the structure must not be in undefined state.  Let examine an alternative way of defining:


struct AlternativeBasicContact {
   
   // Properties
   var name:String
   var no:Int
   
}


If we define the structure as above, we are forced to define the value during instance creation.


The only way to create the instance is to define the value as follows:


var list1 = AlternativeBasicContact(name: "Steve", no: 827324)


If our structure was defined with default value or null value, then we can create the instance without entering any value. Please note that creating such instance in constant is meaningless because we cannot change the property value later.


struct AnotherBasicContact {
   
   // Properties
   
   // initialized with blank
   var name = ""
   
   // initialized to zero
   var no = Int()
   
   // optional are initialized to nil
   var gotemail:Bool?
   
}


We can create instance of the above defined structure without any value:


var anotherContact1 = AnotherBasicContact()



Accessing Properties

We access properties using the same method as tuples. We use the dot to access properties. See example below:


list1.maxLengthName
list1.name
list1.no

print("The contact number of \(list2.name) is \(list2.no)")



Setting Properties

While we can access properties, we can also set properties. However, there is a catch. It depends on how we create the instances.


  • If the instances is variable, we can set those properties that are defined as variables.
  • If the instances is variable, we cannot set those properties that are defined as constant.
  • If the instances is constant, we cannot set any properties including properties that are defined as variables.


Look at our first example, let us try to set some value since it is empty.


list1.name = "Steve"
list1.no = 82370293
list1.maxLengthName = 60


As shown above, we cannot set maxLengthName as it is defined as constant. If we comment out the last code, we can set and access the name and number of BasicContact.


list1.name = "Steve"
list1.no = 82370293

list1.name
list1.no


What is Instances Method?

Methods are functions that belong to a structure. Instances method are function that belong to an instances of structure.


Now, we add a print function to the structure defined earlier


struct BasicContact {
   
   // Properties
   var name = String()
   var no  = Int()
   
   // Constant parameter
   let maxLengthName = 50
   
   // Methods
   func displayName() {
       print("The name of this contact is \(name)")
   }

}


To run the function, we still use the dot(.) to access the function:


list1.displayName()
list2.displayName()



Mutating Methods

In structure, if we need to change the value of the property, we can change outside of structure by accessing the property. Alternatively, we can create a function in the structure to modify its property value.


Using the previous example, we can change the value of name outside structure as shown below:


list1.name
list1.no
list1.name = "newName"
list1.name
list1.no


If we were to implement a function that changed name, we need add the keyword "mutating" in front of func. By putting the keyword, we tell the structure that it is modifying its own properties.


struct BasicContact {
   
   // Properties
   var name = String()
   var no  = Int()
   
   // Constant parameter
   let maxLengthName = 50
   
   // Methods
   func displayName() {
       print("The name of this contact is \(name)")
   }
   
   mutating func changeName(newName: String) {
       name = newName
   }

}


To implement the function, see example below:


list1.name
list1.no
list1.changeName(newName: "Timothy")
list1.name
list1.no



Structure within Structure

We can implement structure within a structure. For example, we have a structure of employee name and contact and a structure of employee work statistics. We can formulate 2 different structure and put it in a third structure as shown below. We do not use tuples because tuples are meant for temporary value holder.


struct EmployeeContact {
   
   // Employee Contacts
   var employeeName = String()
   var emplpyeePhone = Int()
   var employeeAddress = String()
   
}

struct EmployeeWorkSheet {
   
   var employeeID = Int()
   var totalHoursWorked = Int()
   var hourlyPay = Double()
   
}


struct EmployeeWorkInfo {
   var employeeContact = EmployeeContact()
   var employeeWorkData = EmployeeWorkSheet()
   
}


var employee1 = EmployeeWorkInfo()
employee1.employeeContact.employeeName = "Vincent"
employee1.employeeContact.emplpyeePhone = 87758776
employee1.employeeContact.employeeAddress = "Somewhere on earth"
employee1.employeeWorkData.employeeID = 86433
employee1.employeeWorkData.totalHoursWorked = 88
employee1.employeeWorkData.hourlyPay = 35.5




We can also create an array of structure that are defined by a simple structure. See example below:


struct BasicContact {
   
   // Basic Contacts
   var name = String()
   var phone = Int()
   var address = String()
   
}

struct BasicContactList {
   
   var contactList = [BasicContact]()
   
}

var myList = BasicContactList()
var contact1 = BasicContact(name: "Tim", phone: 4123235, address: "california")
var contact2 = BasicContact(name: "Mark", phone: 64578273, address: "Bangkok")

myList.contactList += [contact1, contact2]

myList.contactList[0].name
myList.contactList[0].phone
myList.contactList[0].address
myList.contactList[1].name
myList.contactList[1].phone
myList.contactList[1].address




Implementation of Structure

We can implement the structure using the example in chapter 10. In this example, we create a basic structure that hold the variable for each contact. Then we define a main structure that contain an array of the contact structure.


The code below defines the structure:


// Structure of Contact
struct Contact {
   
   // Properties
   var firstName: String
   var lastName: String
   var mobileNumber:Int
   var email:String
   var twitterHandle:String
}

// Structure of List
struct ContactList {
   
   // Properties
   var contactList = [Contact]()
   
   // Methods
   mutating func loadContactList () {
       
       let contact1 = Contact(firstName: "John", lastName: "Smith", mobileNumber:82736487, email:"john.smith@outlook.com",twitterHandle:"@johmsmith")
       
       let contact2 = Contact(firstName: "Steve", lastName: "Carpenter", mobileNumber:92873432, email:"steve.carpenter@outlook.com",twitterHandle:"@stevecarp")
       
       let contact3 = Contact(firstName: "Mathew", lastName: "Emerson", mobileNumber:9876547, email:"mathew.emerson@gmail.com",twitterHandle:"@matemerson")
       
       contactList += [contact1, contact2, contact3]
       
       print("Load complete")
   }
   
   func displayContactList () {
       
       let total = contactList.count
       for (index, eachContact) in contactList.enumerated() {
           print("Contact \(index)")
           print("First Name: \(eachContact.firstName) Last Name: \(eachContact.lastName)")
           print("Mobile: \(eachContact.mobileNumber)")
           print("Email: \(eachContact.email)")
           print("Twitter: \(eachContact.twitterHandle)")
           
       }
       print("total count = \(total)")
       print("-----------------------------------------")
       
   }

   func storeContactList () {
       
       print("Contact list stored!")
       displayContactList()
   }
   
   mutating func addContact (myContactAdd: Contact) {
       
       contactList.append(myContactAdd)
       
       print("contact added!")
   }
   
   mutating func removeContact (index: Int) {
       
       contactList.remove(at: index)
       print("contact removed")
   }
   
   mutating func editContact (index: Int, myContactEdit: Contact) {
       
       contactList[index] = myContactEdit
   }
}


The code below is the implementation of the structure:


// Create Instance
var myContactList = ContactList()


myContactList.loadContactList()
myContactList.displayContactList()


let myContactToAdd = Contact(firstName: "Tom", lastName: "Hilton", mobileNumber: 19289283, email: "tom.hilton@gmail.com", twitterHandle: "@tomh")
myContactList.addContact(myContactAdd: myContactToAdd)
myContactList.displayContactList()


myContactList.removeContact(index: 1)
myContactList.displayContactList()

let contactToEdit = Contact(firstName: "Eric", lastName: "Emerson", mobileNumber: 9876547, email: "eric.emerson@gmail.com", twitterHandle: "@eric")
myContactList.editContact(index: 1, myContactEdit: contactToEdit)
myContactList.displayContactList()

myContactList.storeContactList()


The result screenshot for 3rd and 4th line of code above


The result after we added a new contact


The result after we removed 1 contact:


The result after we edited one contact:


The final screenshot where we store the data. In this case, we just display the list of contact.


In the example above, we created 2 structures and the ContactList structure holds all the functions and the array. We can also put the BasicContact structure with the ContactList. The definition and implementation will be slightly different.


// Structure of List
struct ContactList {
   
   // Structure of Contact
   struct Contact {
       
       // Properties
       var firstName: String
       var lastName: String
       var mobileNumber:Int
       var email:String
       var twitterHandle:String
   }
   
   // Properties
   var contactList = [Contact]()
   
   // Methods
   mutating func loadContactList () {
       
       let contact1 = Contact(firstName: "John", lastName: "Smith", mobileNumber:82736487, email:"john.smith@outlook.com",twitterHandle:"@johmsmith")
       
       let contact2 = Contact(firstName: "Steve", lastName: "Carpenter", mobileNumber:92873432, email:"steve.carpenter@outlook.com",twitterHandle:"@stevecarp")
       
       let contact3 = Contact(firstName: "Mathew", lastName: "Emerson", mobileNumber:9876547, email:"mathew.emerson@gmail.com",twitterHandle:"@matemerson")
       
       contactList += [contact1, contact2, contact3]
       
       print("Load complete")
   }
   
   func displayContactList () {
       
       let total = contactList.count
       for (index, eachContact) in contactList.enumerated() {
           print("Contact \(index)")
           print("First Name: \(eachContact.firstName) Last Name: \(eachContact.lastName)")
           print("Mobile: \(eachContact.mobileNumber)")
           print("Email: \(eachContact.email)")
           print("Twitter: \(eachContact.twitterHandle)")
           
       }
       print("total count = \(total)")
       print("-----------------------------------------")
       
   }

   func storeContactList () {
       
       print("Contact list stored!")
       displayContactList()
   }
   
   mutating func addContact (myContactAdd: Contact) {
       
       contactList.append(myContactAdd)
       
       print("contact added!")
   }
   
   mutating func removeContact (index: Int) {
       
       contactList.remove(at: index)
       print("contact removed")
   }
   
   mutating func editContact (index: Int, myContactEdit: Contact) {
       
       contactList[index] = myContactEdit
   }
}


The implementation code is as follows:


// Create Instance
var myContactList = ContactList()


myContactList.loadContactList()
myContactList.displayContactList()


let myContactToAdd = ContactList.Contact(firstName: "Tom", lastName: "Hilton", mobileNumber: 19289283, email: "tom.hilton@gmail.com", twitterHandle: "@tomh")
myContactList.addContact(myContactAdd: myContactToAdd)
myContactList.displayContactList()


myContactList.removeContact(index: 1)
myContactList.displayContactList()

let contactToEdit = ContactList.Contact(firstName: "Eric", lastName: "Emerson", mobileNumber: 9876547, email: "eric.emerson@gmail.com", twitterHandle: "@eric")
myContactList.editContact(index: 1, myContactEdit: contactToEdit)
myContactList.displayContactList()

myContactList.storeContactList()


The only difference is when we create an instance of the the contact.



Please note that there are many more features in defining structures. We leave it for the advance implementation.

***

No comments:

Post a Comment