Premium projects bundle

Buy the 14 premium projects bundle for $1000. The bundle contains projects in the following technologies:

  • Node JS and Mongo DB
  • PHP & MySQL, Laravel
  • Vue JS
  • Android apps

Project’s list

  1. Single page chat application – Vue JS, Node JS, Mongo DB
  2. E-commerce single page application – Vue JS, Node JS, Mongo DB
  3. Chat app – Android, Web admin panel
  4. Email marketing tool – Laravel, Vue JS
  5. Financial ledger – Vue JS, Node JS, Mongo DB
  6. Image sharing web app – Node JS, Mongo DB / MySQL
  7. Movie ticket booking site – PHP & MySQL, MVC
  8. Realtime blog in Node JS and Mongo DB
  9. File transfer web app – Node JS + Mongo DB
  10. Realtime customer support chat widget
  11. Video streaming website – Node JS, Mongo DB
  12. Picture competition web app – Node JS, Mongo DB
  13. Questionnaire – Node JS, Mongo DB
  14. Blog website – Laravel, Google Adsense approved

You can buy each project separately too as well. Besides getting all the pro features of all 14 projects, we also provide additional services to them.

Secure payment

We allow users to make payments easily and securely using their bank accounts. You can contact us here and we will send you an invoice to make the payment.

Source code

Complete source code is included in all the projects. You will enjoy the pro version of each project.

Support

If you encounter any problem in installing the project or deployment, our technical support team is here. You can schedule a meeting with them and they will be able to assist you over AnyDesk or TeamViewer.

Use as a college project

If you are a student and are looking to get ready-to-go projects to learn about code and how real projects work, this will be beneficial for you. Also, Node JS projects are good learning points for students in advanced programming.

Customize as you want

Once you download the projects, you can customize them as per your needs. You can change the color theme, add new features to it, etc.

Get help in deployment

Once projects are set up in your local host, we will be here if you needed any help in deployment to the live server. For Node JS projects, we will assist you in deployment to Heroku. And for Mongo DB projects, we will help you with a deployment to mongodb.com.

Price: $1000

Out TrustPilot reviews

TrustPilot-reviews
TrustPilot-reviews

Search bar Swift UI with history – SQLite

SQLite is used to store the data locally inside the app in SQL structure. It is a relational local database. You can use this database to store data inside the app using Swift and Swift UI. We will be creating a simple search bar in an iOS app in Swift UI to search animals from an array and save the user’s searched strings in the SQLite database.

We will be using a library called SQLite by Stephen Celis. To install this library, you must have Cocoapods installed in your system.

Installation

You can install Cocoapods in your system by simply running the following command in your terminal:

1
sudo gem install cocoapods

First, you need to open a command prompt (Terminal) at the root of your XCode project and run the following command in it:

1
pod init

Now you will see a new file created at the root of your project named Podfile. Open that file in your text editor and add the line to install the library. Following will be the content of your Podfile:

1
2
3
4
5
6
7
8
9
10
11
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
  
target 'SQLite_Database' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!
  
  # Pods for SQLite_Database
  pod 'SQLite.swift', '~> 0.12.0'
  
end

After that, run the following command in your Terminal to install this library:

1
pod update

Once installed, close your XCode and re-open but this time double-click on the file which has an extension “.xcworkspace“. This file will be created only after the pod has been installed/updated.

Create a search bar

First, we will create a search bar using TextField. Then, when the user hits submit, we will send the searched value in the next view.

In the second view, we will get the value from the text field of the first view and search that value in an array. Then, display all the records that matched the searched string and display them in the list view.

Create a state variable in your content view:

1
2
3
4
5
// variable to goto search view
@State var gotoSearchPage: Bool = false
 
// value that is searched from the text field
@State var searchedText: String = ""

Following will be the content of your content view’s body:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// live tracking of input field value
let binding = Binding<String>(get: {
    self.searchedText
}, set: { (value) in
    self.searchedText = value
})
 
// navigation view to goto search view
return NavigationView {
 
    VStack (alignment: .leading, spacing: 10) {
     
        // navigation link to goto search view
        NavigationLink (destination: SearchView(searchedText: self.$searchedText), isActive: self.$gotoSearchPage) {
            EmptyView()
        }
     
        // search field
        TextField("Search ...", text: binding, onCommit: {
         
            // goto search view when search icon is clicked
            self.gotoSearchPage = true
         
        })
            .padding(7)
            .padding(.horizontal, 5)
            .background(Color(.systemGray6))
            .cornerRadius(8)
            .disableAutocorrection(true)
            .keyboardType(.webSearch)
         
    }
    .padding(20)
    .navigationBarTitle("Search - SQLite")
}

This will create a text field where you can enter your query, on hitting the “search icon” it should take you to the search view which we will create in the next step.

Create a search view

Now, we need to create a search view where we will perform the searching and display the filtered records in a list view.

Create a modal class for Animal:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//
//  Animal.swift
//  Search bar with history
//
//  Created by Adnan Afzal on 02/12/2020.
//  Copyright © 2020 Adnan Afzal. All rights reserved.
//
 
import Foundation
 
class Animal: Identifiable {
    var id: Int64 = 0
    var name: String = ""
     
    init() {
        //
    }
     
    init(name: String) {
        self.name = name
    }
}

Create a new file named SearchView.swift and paste the following code in it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
//
//  SearchView.swift
//  Search bar with history
//
//  Created by Adnan Afzal on 02/12/2020.
//  Copyright © 2020 Adnan Afzal. All rights reserved.
//
 
import SwiftUI
 
struct SearchView: View {
     
    // get searched value from the previous view
    @Binding var searchedText: String
     
    // a list of all items (change this variable as per your need)
    @State var animals: [Animal] = []
     
    // list of items that matched the searched text
    @State var searchedArray: [Animal] = []
     
    var body: some View {
         
        VStack {
             
            // show searched text
            Text("\(searchedText)").bold()
             
            // show items that matched the searched text in list view
            List (self.searchedArray) { (item) in
                Button(action: {
                    //
                }, label: {
                    Text(item.name)
                })
            }
        }.onAppear(perform: {
         
            // make the items empty when the page loads
            self.animals.removeAll()
             
            // add the data that needs to be searched (you can put your own array items here)
            self.animals.append(Animal(name: "Lion"))
            self.animals.append(Animal(name: "Tiger"))
            self.animals.append(Animal(name: "Rhino"))
            self.animals.append(Animal(name: "Elephant"))
            self.animals.append(Animal(name: "Cheetah"))
            self.animals.append(Animal(name: "Polar bear"))
            self.animals.append(Animal(name: "Leopard"))
            self.animals.append(Animal(name: "Wolf"))
             
            // empty the searched array
            self.searchedArray.removeAll()
             
            // find all the elements that matched the searched string
            for animal in self.animals {
                if (animal.name.lowercased().contains(self.searchedText.lowercased())) {
                    self.searchedArray.append(animal)
                }
            }
        })
         
    }
}
 
struct SearchView_Previews: PreviewProvider {
 
    // when using @Binding, use this in preview provider
    @State static var searchedText: String = ""
 
    static var previews: some View {
        SearchView(searchedText: $searchedText)
    }
}

Comments have been added on each line to explain each line individually. Now, at this point, you will be able to perform the search and see the animals which contain the name field that matches with the text field value you entered in the first view.

Show search history

Now, we need to show the search history in the content view. For that, first, we have to save each searched string in the SQLite database.

Create a separate class named “DB_Manager” that will hold all the functions for the SQLite database.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
//
//  DB_Manager.swift
//  Search bar with history
//
//  Created by Adnan Afzal on 02/12/2020.
//  Copyright © 2020 Adnan Afzal. All rights reserved.
//
 
import Foundation
 
// import library
import SQLite
 
class DB_Manager {
 
    // sqlite instance
    private var db: Connection!
      
    // table instance
    private var animals: Table!
  
    // columns instances of table
    private var id: Expression<Int64>!
    private var name: Expression<String>!
     
    // constructor of this class
    init () {
          
        // exception handling
        do {
              
            // path of document directory
            let path: String = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first ?? ""
  
            // creating database connection
            db = try Connection("\(path)/my_animals.sqlite3")
              
            // creating table object
            animals = Table("animals")
              
            // create instances of each column
            id = Expression<Int64>("id")
            name = Expression<String>("name")
              
            // check if the animal's table is already created
            if (!UserDefaults.standard.bool(forKey: "is_db_created")) {
  
                // if not, then create the table
                try db.run(animals.create { (t) in
                    t.column(id, primaryKey: true)
                    t.column(name)
                })
                  
                // set the value to true, so it will not attempt to create the table again
                UserDefaults.standard.set(true, forKey: "is_db_created")
            }
              
        } catch {
            // show error message if any
            print(error.localizedDescription)
        }
          
    }
 
    // check if record already exists in SQLite
    public func isExists(searchedText: String) -> Bool {
      
        var isExists: Bool = false
          
        // exception handling
        do {
      
            // get animal using ID
            let animal: AnySequence<Row> = try db.prepare(animals.filter(name.lowercaseString == searchedText.lowercased()))
      
            // get row
            animal.forEach({ (rowValue) in
                isExists = true
            })
             
        } catch {
            print(error.localizedDescription)
        }
      
        return isExists
    }
     
    // add a new row in SQLite
    public func addAnimal(nameValue: String) {
        do {
            try db.run(animals.insert(name <- nameValue))
        } catch {
            print(error.localizedDescription)
        }
    }
     
}

Comments have been added with each line for an explanation. Now, in your search view inside the onAppear() function, check if the searched string already exists in the SQLite database. If NOT, then add the searched text in the SQLite database.

1
2
3
4
5
// add the searched text in SQLite database if NOT exists
let isExists: Bool = DB_Manager().isExists(searchedText: self.searchedText)
if (!isExists) {
    DB_Manager().addAnimal(nameValue: self.searchedText)
}

Now, we need to show the search history in the main content view when the user clicks on the search bar text field. So, create 2 state wrapper properties in your content view:

1
2
3
4
5
// variable to show search history view
@State var showSearchHistoryView: Bool = false
 
// array of history array
@State var history: [Animal] = []

And inside the body, we need to track the live text change of the input field. We have already created a binding variable inside the body of the content view. Change the binding variable inside the content view body to the following:

1
2
3
4
5
6
7
8
9
// live tracking of input field value
let binding = Binding<String>(get: {
    self.searchedText
}, set: { (value) in
    self.searchedText = value
     
    // show history if the text field is not empty
    self.showSearchHistoryView = !self.searchedText.isEmpty
})

Now, when the showSearchHistoryView variable is true, we need to display a list of all previously searched strings. So, create a list view under an if condition below the search bar text field:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// show history view only when a variable is true
if (self.showSearchHistoryView) {
     
    // create list view to show all history items
    List (self.history) { (model) in
     
        // show history text
        HStack {
         
            Image(systemName: "arrow.counterclockwise")
         
            Button(action: {
                self.searchedText = model.name
                self.gotoSearchPage = true
            }, label: {
                Text(model.name)
            })
 
        }
    }
}

This will display a counter clock icon that represents that it is data from history, a button that shows the previously searched string, and which when clicked will move to the search view.

Now, we need to load the data in our history array. So, attach an onAppear() event to your VStack and fetch the data from the SQLite database and save it in the history array.

1
2
3
4
// load data in history models array
.onAppear(perform: {
    self.history = DB_Manager().getAnimals()
})

Now, we need to create a function named getAnimals() in our DB_Manager class that will fetch the records from the SQLite database.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// return array of animal models
public func getAnimals() -> [Animal] {
      
    // create empty array
    var animalModels: [Animal] = []
  
    // get all animals in descending order
    animals = animals.order(id.desc)
  
    // exception handling
    do {
  
        // loop through all animals
        for animal in try db.prepare(animals) {
  
            // create new model in each loop iteration
            let animalModel: Animal = Animal()
  
            // set values in model from database
            animalModel.id = animal[id]
            animalModel.name = animal[name]
  
            // append in new array
            animalModels.append(animalModel)
        }
    } catch {
        print(error.localizedDescription)
    }
  
    // return array
    return animalModels
}

Comments have been added with each line for an explanation. If you run the code now, you will be able to view all the searched strings in a list view, upon click it will take you to the search view screen.

At this point, the search bar in Swift UI is completed. But you can go further and add the delete functionality. So user can remove his searched queries.

Delete history

Now, we need a function to delete the string from search history. First, create a button inside your history list after the counter-clock icon and button in your content view:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
... counter-clock icon and button
 
// show delete button
Spacer()
Button(action: {
     
    // delete history item from SQLite
    DB_Manager().deleteAnimal(idValue: model.id)
     
    // refresh the list view
    self.history = DB_Manager().getAnimals()
     
}, label: {
    Text("Delete")
        .foregroundColor(Color.red)
})// by default, buttons are full width.
// to prevent this, use the following
.buttonStyle(PlainButtonStyle())

Now, we need to create a function named deleteAnimal() in our DB_Manager class that will delete the row from the SQLite database.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// function to delete animal from search history
public func deleteAnimal(idValue: Int64) {
    do {
     
        // get animal using ID
        let animal: Table = animals.filter(id == idValue)
          
        // run the delete query
        try db.run(animal.delete())
         
    } catch {
        print(error.localizedDescription)
    }
}

Run the code now, and you will be able to see a delete button at the end of each history row. Upon clicking, it will remove the row from the SQLite database and from the list view as well.

So you have successfully created a search bar in Swift UI along with search history.

You can also learn to create a UICollectionView with a search bar from the following tutorial.

UICollectionview with Search Bar – Swift iOS

[wpdm_package id=’929′]

Swift UI SQLite – Create, Read, Update and Delete in Swift

SQLite is used to store the data locally inside the app in SQL structure. It is a relational local database. You can use the SQLite database to store data inside the app using Swift and Swift UI.

We will be creating a simple iOS app in Swift UI to create, read, update, and delete users from the SQLite database.

We will be using a library called SQLite by Stephen Celis. To install this library, you must have Cocoapods installed in your system.

Installation

You can install Cocoapods in your system by simply running the following command in your terminal:

1
sudo gem install cocoapods

First, you need to open a command prompt (Terminal) at the root of your XCode project and run the following command in it:

1
pod init

Now you will see a new file created at the root of your project named Podfile. Open that file in your text editor and add the line to install the library. Following will be the content of your Podfile:

1
2
3
4
5
6
7
8
9
10
11
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
 
target 'SQLite_Database' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!
 
  # Pods for SQLite_Database
  pod 'SQLite.swift', '~> 0.12.0'
 
end

After that, run the following command in your Terminal to install this library:

1
pod update

Once installed, close your XCode and re-open but this time double-click on the file which has an extension “.xcworkspace“. This file will be created only after the pod has been installed/updated.

1. Add user

First, we will create a model class that will hold the data structure for each user. Create a file named “UserModel.swift” and paste the following code in it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//
//  UserModel.swift
//  SQLite_Database
//
//  Created by Adnan Afzal on 24/11/2020.
//  Copyright © 2020 Adnan Afzal. All rights reserved.
//
 
import Foundation
 
class UserModel: Identifiable {
    public var id: Int64 = 0
    public var name: String = ""
    public var email: String = ""
    public var age: Int64 = 0
}

Your model class must conform to Identifiable protocol in order to show the users in List view.

DB_Manager.swift

To handle the database functions, we will create a separate file named “DB_Manager.swift“. In this class, we will create the database, tables and it’s columns in the constructor.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
//
//  DB_Manager.swift
//  SQLite_Database
//
//  Created by Adnan Afzal on 24/11/2020.
//  Copyright © 2020 Adnan Afzal. All rights reserved.
//
 
import Foundation
 
// import library
import SQLite
 
class DB_Manager {
     
    // sqlite instance
    private var db: Connection!
     
    // table instance
    private var users: Table!
 
    // columns instances of table
    private var id: Expression<Int64>!
    private var name: Expression<String>!
    private var email: Expression<String>!
    private var age: Expression<Int64>!
     
    // constructor of this class
    init () {
         
        // exception handling
        do {
             
            // path of document directory
            let path: String = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first ?? ""
 
            // creating database connection
            db = try Connection("\(path)/my_users.sqlite3")
             
            // creating table object
            users = Table("users")
             
            // create instances of each column
            id = Expression<Int64>("id")
            name = Expression<String>("name")
            email = Expression<String>("email")
            age = Expression<Int64>("age")
             
            // check if the user's table is already created
            if (!UserDefaults.standard.bool(forKey: "is_db_created")) {
 
                // if not, then create the table
                try db.run(users.create { (t) in
                    t.column(id, primaryKey: true)
                    t.column(name)
                    t.column(email, unique: true)
                    t.column(age)
                })
                 
                // set the value to true, so it will not attempt to create the table again
                UserDefaults.standard.set(true, forKey: "is_db_created")
            }
             
        } catch {
            // show error message if any
            print(error.localizedDescription)
        }
         
    }
}

Comments have been added with each line for clarification. Now, in your content view, we will create a navigation link that will move to the AddUserView file.

AddUserView.swift

Open your content view file and place this code inside the body:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// create navigation view
NavigationView {
 
    VStack {
 
        // create link to add user
        HStack {
            Spacer()
            NavigationLink (destination: AddUserView(), label: {
                Text("Add user")
            })
        }
 
        // list view goes here
 
    }.padding()
    .navigationBarTitle("SQLite")
}

Now, create a new view file named “AddUserView.swift” and paste the following code in it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//
//  AddUserView.swift
//  SQLite_Database
//
//  Created by Adnan Afzal on 24/11/2020.
//  Copyright © 2020 Adnan Afzal. All rights reserved.
//
 
import SwiftUI
 
struct AddUserView: View {
     
    // create variables to store user input values
    @State var name: String = ""
    @State var email: String = ""
    @State var age: String = ""
     
    // to go back on the home screen when the user is added
    @Environment(\.presentationMode) var mode: Binding<PresentationMode>
     
    var body: some View {
         
        VStack {
            // create name field
            TextField("Enter name", text: $name)
                .padding(10)
                .background(Color(.systemGray6))
                .cornerRadius(5)
                .disableAutocorrection(true)
             
            // create email field
            TextField("Enter email", text: $email)
                .padding(10)
                .background(Color(.systemGray6))
                .cornerRadius(5)
                .keyboardType(.emailAddress)
                .autocapitalization(.none)
                .disableAutocorrection(true)
             
            // create age field, number pad
            TextField("Enter age", text: $age)
                .padding(10)
                .background(Color(.systemGray6))
                .cornerRadius(5)
                .keyboardType(.numberPad)
                .disableAutocorrection(true)
             
            // button to add a user
            Button(action: {
                // call function to add row in sqlite database
                DB_Manager().addUser(nameValue: self.name, emailValue: self.email, ageValue: Int64(self.age) ?? 0)
                 
                // go back to home page
                self.mode.wrappedValue.dismiss()
            }, label: {
                Text("Add User")
            })
                .frame(maxWidth: .infinity, alignment: .trailing)
                .padding(.top, 10)
                .padding(.bottom, 10)
        }.padding()
         
    }
}

This is a bit lengthy but comments have been added with each line for an explanation.

At this point, you will see an error in the highlighted line. Because we have to create that function in our DB manager class. So, create the following function in your DB_Manager.swift file:

1
2
3
4
5
6
7
public func addUser(nameValue: String, emailValue: String, ageValue: Int64) {
    do {
        try db.run(users.insert(name <- nameValue, email <- emailValue, age <- ageValue))
    } catch {
        print(error.localizedDescription)
    }
}

If you run the app now, you will a link to add a user view, on that view you will see 3 fields. After filling the fields and hitting the submit button, the data will be saved in the SQLite database and you will be moved to the home view.

However, you will not see the data that has been saved in the database. So now we will show the data in List view.

2. View all users

In your content view, where you want to show all the data from the database, create a state property wrapper:

1
2
// array of user models
@State var userModels: [UserModel] = []

Now, create a list view in the content view body after the navigation link for adding a user view:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// create list view to show all users
List (self.userModels) { (model) in
 
    // show name, email and age horizontally
    HStack {
        Text(model.name)
        Spacer()
        Text(model.email)
        Spacer()
        Text("\(model.age)")
        Spacer()
 
        // edit and delete button goes here
    }
}

When the content view is loaded, we need to add the data from the database in that userModels array. Attach an onAppear function at the end of your VStack like below:

1
2
3
4
5
6
7
VStack {
    ...
}
// load data in user models array
.onAppear(perform: {
    self.userModels = DB_Manager().getUsers()
})

Now, we need to create a function named getUsers() in our DB manager class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// return array of user models
public func getUsers() -> [UserModel] {
     
    // create empty array
    var userModels: [UserModel] = []
 
    // get all users in descending order
    users = users.order(id.desc)
 
    // exception handling
    do {
 
        // loop through all users
        for user in try db.prepare(users) {
 
            // create new model in each loop iteration
            let userModel: UserModel = UserModel()
 
            // set values in model from database
            userModel.id = user[id]
            userModel.name = user[name]
            userModel.email = user[email]
            userModel.age = user[age]
 
            // append in new array
            userModels.append(userModel)
        }
    } catch {
        print(error.localizedDescription)
    }
 
    // return array
    return userModels
}

This will fetch the users from the SQLite database in descending order (latest users first) and return them as an array of user model classes.

Run the app and now you will see the users that have been added in a tabular format. You can try removing the app from the background and open again, the data will still be there. Data will only be removed when the app is uninstalled.

3. Edit user

Editing the user requires multiple steps:

  1. Get user by ID.
  2. Show user details in input fields.
  3. Update the user in the database using his ID.

First, we need to create 2 state variables at the top of the content view which will tell WHEN the user is selected for editing and WHICH user is selected.

1
2
3
4
5
// check if user is selected for edit
@State var userSelected: Bool = false
 
// id of selected user to edit or delete
@State var selectedUserId: Int64 = 0

Now, in your HStack inside the list view, create a button to edit the user:

1
2
3
4
5
6
7
8
9
10
11
// button to edit user
Button(action: {
    self.selectedUserId = model.id
    self.userSelected = true
}, label: {
    Text("Edit")
        .foregroundColor(Color.blue)
    })
    // by default, buttons are full width.
    // to prevent this, use the following
    .buttonStyle(PlainButtonStyle())

This will set the userSelected variable to true, and selectedUserId to the ID of the user you have selected. Now we need to move to the new view to edit the user.

Create a navigation link with an empty view, inside the content view body and before the list view:

1
2
3
4
// navigation link to go to edit user view
NavigationLink (destination: EditUserView(id: self.$selectedUserId), isActive: self.$userSelected) {
    EmptyView()
}

EditUserView.swift

Create a new view file named EditUserView.swift and paste the following code into it. Pay close attention to the highlighted lines:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
//
//  EditUserView.swift
//  SQLite_Database
//
//  Created by Adnan Afzal on 24/11/2020.
//  Copyright © 2020 Adnan Afzal. All rights reserved.
//
 
import SwiftUI
 
struct EditUserView: View {
     
    // id receiving of user from previous view
    @Binding var id: Int64
     
    // variables to store value from input fields
    @State var name: String = ""
    @State var email: String = ""
    @State var age: String = ""
     
    // to go back to previous view
    @Environment(\.presentationMode) var mode: Binding<PresentationMode>
     
    var body: some View {
        VStack {
            // create name field
            TextField("Enter name", text: $name)
                .padding(10)
                .background(Color(.systemGray6))
                .cornerRadius(5)
                .disableAutocorrection(true)
             
            // create email field
            TextField("Enter email", text: $email)
                .padding(10)
                .background(Color(.systemGray6))
                .cornerRadius(5)
                .keyboardType(.emailAddress)
                .autocapitalization(.none)
                .disableAutocorrection(true)
             
            // create age field, number pad
            TextField("Enter age", text: $age)
                .padding(10)
                .background(Color(.systemGray6))
                .cornerRadius(5)
                .keyboardType(.numberPad)
                .disableAutocorrection(true)
             
            // button to update user
            Button(action: {
                // call function to update row in sqlite database
                DB_Manager().updateUser(idValue: self.id, nameValue: self.name, emailValue: self.email, ageValue: Int64(self.age) ?? 0)
 
                // go back to home page
                self.mode.wrappedValue.dismiss()
            }, label: {
                Text("Edit User")
            })
                .frame(maxWidth: .infinity, alignment: .trailing)
                .padding(.top, 10)
                .padding(.bottom, 10)
        }.padding()
 
        // populate user's data in fields when view loaded
        .onAppear(perform: {
             
            // get data from database
            let userModel: UserModel = DB_Manager().getUser(idValue: self.id)
             
            // populate in text fields
            self.name = userModel.name
            self.email = userModel.email
            self.age = String(userModel.age)
        })
    }
}
 
struct EditUserView_Previews: PreviewProvider {
     
    // when using @Binding, do this in preview provider
    @State static var id: Int64 = 0
     
    static var previews: some View {
        EditUserView(id: $id)
    }
}

@Binding is used when you want to pass the value from one view to another. In that case, if you are using preview provider, then you have to create the @State variable in it.

At this time, you will be getting error at DB_Manager().updateUser and DB_Manager().getUser because these functions are not yet created in DB manager class.

First, we will create the function to get the single user from SQLite database using his ID. In your DB_Manager.swift:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// get single user data
public func getUser(idValue: Int64) -> UserModel {
 
    // create an empty object
    let userModel: UserModel = UserModel()
     
    // exception handling
    do {
 
        // get user using ID
        let user: AnySequence<Row> = try db.prepare(users.filter(id == idValue))
 
        // get row
        try user.forEach({ (rowValue) in
 
            // set values in model
            userModel.id = try rowValue.get(id)
            userModel.name = try rowValue.get(name)
            userModel.email = try rowValue.get(email)
            userModel.age = try rowValue.get(age)
        })
    } catch {
        print(error.localizedDescription)
    }
 
    // return model
    return userModel
}

The filter function at the highlighted line helps to perform the WHERE clause (to filter the data).

Now we need to create a function in the DB manager class to update the user in the SQLite database.

1
2
3
4
5
6
7
8
9
10
11
12
// function to update user
public func updateUser(idValue: Int64, nameValue: String, emailValue: String, ageValue: Int64) {
    do {
        // get user using ID
        let user: Table = users.filter(id == idValue)
         
        // run the update query
        try db.run(user.update(name <- nameValue, email <- emailValue, age <- ageValue))
    } catch {
        print(error.localizedDescription)
    }
}

Here, we are first getting the user object using the filter() function. Then we are running the update query on that user’s object.

Run the app and now you will see an “Edit” button at the end of each user’s record. Clicking on that will take you to another view, from where you will see the user’s data in input fields. Clicking the “Update” button will update the data and move it back to the home view.

4. Delete user

To delete a user from the SQLite database in Swift UI, first, we will create a delete button in the list view like we created the edit button.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// create list view to show all users
List (self.userModels) { (model) in
 
    // show name, email, and age horizontally
    HStack {
        ... edit button
         
        // button to delete user
        Button(action: {
 
            // create db manager instance
            let dbManager: DB_Manager = DB_Manager()
 
            // call delete function
            dbManager.deleteUser(idValue: model.id)
 
            // refresh the user models array
            self.userModels = dbManager.getUsers()
        }, label: {
            Text("Delete")
                .foregroundColor(Color.red)
        })// by default, buttons are full width.
        // to prevent this, use the following
        .buttonStyle(PlainButtonStyle())
    }
}

The above code should be placed after the edit button in the content view. You can see that we created an instance of DB_Manager class and save it in another variable. Because we need to call 2 functions from DB_Manager class.

The first function will delete the user from the SQLite database, and the second function will update the list view. So the delete user will be removed from view as well.

Create the following function in your DB_Manager class:

1
2
3
4
5
6
7
8
9
10
11
12
// function to delete user
public func deleteUser(idValue: Int64) {
    do {
        // get user using ID
        let user: Table = users.filter(id == idValue)
         
        // run the delete query
        try db.run(user.delete())
    } catch {
        print(error.localizedDescription)
    }
}

If you run the app now, you will see a delete button at the end of each user’s record. Clicking that button will remove the user from the database and from the list view as well. You can try removing the app from the background process and re-open it again, the deleted data will not appear again.

Where you can use SQLite in the iOS app?

You can create a feature to save the search history of users locally in the app. So users can re-search the same thing from search history.

You can cache the frequent data in SQLite, so instead of requesting the data from the server, it will be accessed from inside the app. It will increase the performance of your app.

Or you can simply create a server-less app like “Personal account book-keeping app” using SQLite and Swift UI. These type of apps does not require an internet connection to work and the user can use them even without access to the internet.

[wpdm_package id=’923′]

Local storage Swift UI – CRUD

Local storage means the data that is stored inside the app. You do not need an internet connection to create or read data from local storage. We will create a simple iOS app in Swift UI that allows you to create, read, update, and delete values in local storage. For that, we are going to use a built-in class in Swift called UserDefaults.

Note: UserDefaults class must only be used to store singular values, for example, last_login, name, email, etc. It should NOT be used to store data in the tabular form like MySQL, or in embedded form like Mongo DB.

Local Storage

We will create a simple Swift file named LocalStorage.swift. This file will handle the creating, fetching, updating and deleting the data from local storage.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//
//  LocalStorage.swift
//  Local storage CRUD
//
//  Created by Adnan Afzal on 16/11/2020.
//  Copyright © 2020 Adnan Afzal. All rights reserved.
//
 
import Foundation
 
class LocalStorage {
     
    private static let myKey: String = "myKey"
     
    public static var myValue: String {
        set {
            UserDefaults.standard.set(newValue, forKey: myKey)
        }
        get {
            return UserDefaults.standard.string(forKey: myKey) ?? ""
        }
    }
     
    public static func removeValue() {
        UserDefaults.standard.removeObject(forKey: myKey)
    }
     
}
  1. We are creating a static constant named myKey which will hold the name of data.
  2. Then we are creating a static variable named myValue and it has getter and setter. They will automatically be called when we try to save or fetch the value from it.
  3. UserDefaults.standard.string this function returns an optional value, so we have to tell the default value using ?? “”. Here we are setting empty value as default.
  4. Lastly, a static function named removeValue() is created which will remove that value from UserDefaults.

We have made the variables and functions static, so we can use them without creating an object of the LocalStorage class.

You can use the same technique to add as more values as required.

Main Swift UI view

First, we will create a view where we will show 4 buttons to create, view, update, and delete data from UserDefaults. In your main ContentView file, create a navigation view, and inside it create 4 navigation links horizontally.

Right now, we are creating navigation link for AddView only. We will create navigation links for others later in this article.

1
2
3
4
5
6
7
NavigationView {
    HStack {
        NavigationLink (destination: AddView(), label: {
            Text("Add")
        })
    }
}
  1. destination: is the view which will be displayed when this navigation link is clicked
  2. label: is the view that will be displayed to the user.

Add value to local storage

Now create a new Swift UI view file named AddView.swift. In this view, we will create an input field and a button which when clicked will save the text field value in local storage.

To get the value from the text field in Swift UI, we will use the @State property wrapper. First, create a @State variable of type String inside your AddView struct:

1
@State var value: String = ""

Now we can bind this variable in text field’s text value.

1
2
3
4
5
6
7
8
9
VStack {
    TextField("Enter value", text: $value)
 
    Button(action: {
        LocalStorage.myValue = self.value
    }, label: {
        Text("Save")
    })
}
  1. VStack will show the views vertically.
  2. TextField field is created and its value is bound with our value variable.
  3. Button is created with the text “Save” which when clicked will set the myValue variable from LocalStorage class to our value variable.

The setter inside LocalStorage myValue variable will automatically be called when we assign the value. The code inside setter saves the value in UserDefaults.

Get value from local storage

First, we will create a navigation link in our main view to move to a new view to show value from local storage.

1
2
3
4
5
// ContentView.swift
 
NavigationLink (destination: DataView(), label: {
    Text("View")
})

Now create a new Swift UI view file named DataView.swift. This file will simply fetch the value and show it in text view.

1
Text(LocalStorage.myValue)

This will automatically called the getter inside LocalStorage myValue variable. The getter is fetching the value from UserDefaults. If the value is not found, then it is setting the default value to empty string.

Edit value in local storage

First, we will create a navigation link in our main view to move to a new view to update the value in local storage.

1
2
3
4
5
// ContentView.swift
 
NavigationLink (destination: EditView(), label: {
    Text("View")
})

Now create a new Swift UI view file named EditView.swift. Editing the value is almost similar to adding the value. But it has 2 steps:

  1. Show the existing value in text field.
  2. Update the value from text field.

Again, we will create a @State property wrapper in this view:

1
@State var value: String = ""

Then, we will create VStack to show text field and a button vertically. Bound the value variable to text field’s value. Create a button with a text “Update” and setting the local storage value to text field value (same as we did for adding value).

But when the view is loaded, you need to show the existing value in the text field. You can do that by adding an onAppear function to your main view (VStack in my case). In the perform parameter, we will fetch the value from local storage and assign it to our value variable.

As the text field’s text is bound to value variable, so when it’s value is changed, the text field’s text will automatically be changed.

1
2
3
4
5
6
7
8
9
10
11
VStack {
    TextField("Enter value", text: $value)
    Button(action: {
        LocalStorage.myValue = self.value
    }, label: {
        Text("Update")
    })
}
.onAppear(perform: {
    self.value = LocalStorage.myValue
})

Delete a value from local storage

We do not need to create a navigation link to delete. We will simply create a button that when clicked will call the function removeValue() from LocalStorage class.

1
2
3
4
5
Button(action: {
    LocalStorage.removeValue()
}, label: {
    Text("Delete")
})

Your local storage CRUD operation in Swift UI is done here.

[wpdm_package id=’870′]

Send value from one view to another – Swift UI

We will create a text field in one view and send its value into another view. We will be taking an example of a search, you write a text to search in one view and the second view will show you the text you had written on the first view.

Note: When implementing a complete search functionality, you usually show the searched data based on a text query. But this is just an example of how you can implement this.

Video tutorial:

@State property wrapper

We will create 2 @State property wrappers, one to save the value from the text field and the second to show the search page when the user hits the return key.

1
2
3
4
5
// string variable to store search query
@State var searchedText: String = ""
 
// boolean variable to show search view
@State var showSearch: Bool = false

Text field

Now we will create a text field and binds its value to our first variable. As the user types in the input field, we will have its value in that variable.

1
2
3
4
5
6
7
8
9
TextField("Search here...", text: $searchedText, onCommit: {
    // this will be called when the search is clicked
    self.showSearch = true
})
.padding(8)
.keyboardType(.webSearch)
.background(Color(.systemGray6))
.disableAutocorrection(true)
.cornerRadius(5)

Following are the things which needs to understand from above code:

  1. TextField’s first parameter is the string that will be shown to the user.
  2. The second parameter is the binding which will store the text field value in the given variable.
  3. onCommit: is called when the user hits the return key. In this callback, we are setting the showSearch value to true. Note: We will come back to this later.
  4. padding(8): sets the margin between text content and text field borders.
  5. keyboardType(.webSearch): will show a full keyboard with a search icon on bottom right.
  6. background(Color(.systemGray6)): will set the background color of text field to light gray.
  7. disableAutocorrection(true): will disable the auto-correction on this field.
  8. cornerRadius(5): this will make the corners of the text field a little rounded rather than squares.

Pass value to next view

Now we will pass this text field value to next view. This can be done using navigation link:

1
2
3
4
// goto search view
NavigationLink (destination: SearchView(searchedText: $searchedText), isActive: $showSearch) {
    EmptyView()
}

destination is the view which will be shown when the value in isActive becomes true.

Right now, you will get an error in SearchView because we haven’t created that view yet. Also, we are sending searchedText as a parameter which means that we have to create a @Binding property wrapper in search view.

The EmptyView() is the label that is shown in the first view. But we don’t want any text to be displayed on the initial value, so we are making it an empty view.

When using navigation link, you must wrap your outer parent with navigation view. So your view body will be like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
NavigationView {
    VStack {
         
        // goto search view
        NavigationLink (destination: SearchView(searchedText: $searchedText), isActive: $showSearch) {
            EmptyView()
        }
         
        TextField("Search here...", text: $searchedText, onCommit: {
            // this will be called when the search is clicked
            self.showSearch = true
        })
        .padding(8)
        .keyboardType(.webSearch)
        .background(Color(.systemGray6))
        .disableAutocorrection(true)
        .cornerRadius(5)
         
    }.padding()
}

Search view

Now, create another view file in your project named SearchView.swift. As we are sending a searched text in its constructor, so we must add a @Binding variable in it:

1
2
// @Binding is used when variables need to be passed between 2 views
@Binding var searchedText: String

Now, you might get the error in your preview provider code. It is because we need to pass the value from here as well. Replace your preview provider body code with the following:

1
2
3
4
5
6
// when using @Binding, @State static must be used to show preview
@State static var searchedText: String = ""
 
static var previews: some View {
    SearchView(searchedText: $searchedText)
}

Now, inside the body of view, we are simply displaying the searched value in a text. But you can use it in any way you want.

1
2
3
4
5
// show searched text in this view
         
VStack {
    Text(self.searchedText)
}

That’s how you can send value from one view to another using Swift UI.

[wpdm_package id=’865′]

Pick image from gallery and upload to server – SwiftUI and PHP

Learn how to upload image from SwiftUI app. We will not be using any external library in this tutorial. All code is done in native SwiftUI. We will use a picker from an iPhone gallery and upload it to your server. We will be using SwiftUI for developing the app and PHP for uploading the image to the server.

First, you need to create a file in your project named ImagePicker.swift and paste the following content in it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
//
//  ImagePicker.swift
//
//  Created by Adnan Afzal on 30/10/2020.
//  Copyright © 2020 Adnan Afzal. All rights reserved.
//
 
import Foundation
import SwiftUI
 
extension View {
    public func asUIImage() -> UIImage {
        let controller = UIHostingController(rootView: self)
         
        controller.view.frame = CGRect(x: 0, y: CGFloat(Int.max), width: 1, height: 1)
        UIApplication.shared.windows.first!.rootViewController?.view.addSubview(controller.view)
         
        let size = controller.sizeThatFits(in: UIScreen.main.bounds.size)
        controller.view.bounds = CGRect(origin: .zero, size: size)
        controller.view.sizeToFit()
         
        // here is the call to the function that converts UIView to UIImage: `.asImage()`
        let image = controller.view.asUIImage()
        controller.view.removeFromSuperview()
        return image
    }
}
 
extension UIView {
// This is the function to convert UIView to UIImage
    public func asUIImage() -> UIImage {
        let renderer = UIGraphicsImageRenderer(bounds: bounds)
        return renderer.image { rendererContext in
            layer.render(in: rendererContext.cgContext)
        }
    }
}
 
struct ImagePicker: UIViewControllerRepresentable {
 
    @Environment(\.presentationMode)
    var presentationMode
 
    @Binding var image: Image?
 
    class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
 
        @Binding var presentationMode: PresentationMode
        @Binding var image: Image?
 
        init(presentationMode: Binding<PresentationMode>, image: Binding<Image?>) {
            _presentationMode = presentationMode
            _image = image
        }
 
        func imagePickerController(_ picker: UIImagePickerController,
                                   didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            let uiImage = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
            image = Image(uiImage: uiImage)
            presentationMode.dismiss()
 
        }
 
        func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
            presentationMode.dismiss()
        }
 
    }
 
    func makeCoordinator() -> Coordinator {
        return Coordinator(presentationMode: presentationMode, image: $image)
    }
 
    func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
        let picker = UIImagePickerController()
        picker.delegate = context.coordinator
        return picker
    }
 
    func updateUIViewController(_ uiViewController: UIImagePickerController,
                                context: UIViewControllerRepresentableContext<ImagePicker>) {
 
    }
 
}

Now we have created a video tutorial to help you done this task. You can follow the video below:

[wpdm_package id=’867′]

UITableView with search – Swift iOS

In this tutorial, we are going to teach you, how you can create a UITableView with search bar in iOS using Swift 4. Following are the steps:

Video tutorial:

  1. Create a new project in XCode.
  2. Drag and drop a “Table view” in your storyboard.
  3. Open assistant from top menu bar Editor > Assistant.
  4. Hold shift and drag & drop your tableview in your controller to create an outlet. Give it a name like “tableview”.
1
@IBOutlet weak var tableview: UITableView!
  1. Connect datasource and delegate of your table view with your controller.
  2. Extend your view controller from UITableViewDataSource and UITableViewDelegate.
1
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
  1. Create an array of data, you might be getting this from API:
1
private var array: [String] = ["Cow", "Lion", "Wolf", "Camel", "Tiger"]
  1. Now register your table view with Swift built-in table view cell:
1
2
3
4
5
6
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
     
    self.tableview.register(UITableViewCell.self, forCellReuseIdentifier: "cellIdentifier")
}
  1. Now create 3 functions:
    • 1st will return the total number of items needs to be displayed in table view.
    • 2nd will display the values from array in each table view cell.
    • 3rd will be called whenever any cell item is being tapped or clicked.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.array.count
}
 
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell: UITableViewCell = self.tableview.dequeueReusableCell(withIdentifier: "cellIdentifier")!
     
    cell.textLabel?.text = self.array[indexPath.row]
     
    return cell
}
 
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    print(self.array[indexPath.row])
}
  1. Then drag and drop “Search bar” in your storyboard at the top of table view and create its outlet in your controller same as you did in step 4.
1
@IBOutlet weak var searchBar: UISearchBar!

At this point, you can see the UITableView with search on top in the XCode preview. But we need to make it functional.

  1. Join it’s delegate with your controller same as in step 5.
  2. Implement the UISearchBarDelegate in your controller class:
1
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate {
  1. Create another array which will hold the initial values:
1
private var initialArray: [String] = ["Cow", "Lion", "Wolf", "Camel", "Tiger"]
  1. Finally, create a function which will be called whenever you type something in the search bar. This function search the text in all the initial values of array. You can make the search case insensitive by making both the text lowercased, text of search bar and of array. We also have to put a condition that when the search bar is empty, then we will display all the values from initial array. Lastly, you need to reload the data in table view in order to see searched data.
1
2
3
4
5
6
7
8
9
10
11
12
13
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    let text: String = self.searchBar.text ?? ""
    self.array = []
    for item in self.initialArray {
        if (item.lowercased().contains(text.lowercased())) {
            self.array.append(item)
        }
    }
    if (text.isEmpty) {
        self.array = self.initialArray
    }
    self.tableview.reloadData()
}

Follow more iOS tutorials.

[wpdm_package id=’727′]

What to do if you accidentally delete your files during iCloud upload – Mac

We all make mistakes. Sometimes, we do not know what is going to happen because of our lack of knowledge. You may try to upload the files on iCloud. And when you delete them from the iCloud, they might get deleted from your computer as well.

To prevent this, follow these steps:

  1. First, disable your iCloud from  ->System Preferences -> Apple ID
    • Uncheck “iCloud Drive“.
    • It will say that it will delete all the files from “Documents and Desktop”. You will also see the option “Keep a Copy“.
    • Click on “Keep a Copy
    • DO NOT click “Turn off update and disable iCloud“. I repeat, DO NOT click on it.
    • Let it finish the backup. Once done it will take the backup and delete all files from Documents and Desktop
    • Don’t worry, you can get them back.
  2. Now your iCloud should be disabled. Now open your Finder and from top menu bar, goto Go -> Home. This will open a folder with your username on it.
  3. In this folder, you will see a folder named “iCloud Archive“. The name can also have a date in it.
  4. In this folder you will have all your copied files. You can copy them again into your Documents and Desktop folder. And remove them from the Archive folder if you want.

I am writing this because I got myself a problem like this during my iCloud upload. As I searched, I find out there are a lot of people who are finding difficult to recover their files. So I thought I would better share the solution that worked for me and it may help someone who find himself in such trouble.

If you want to password protect your ZIP files in Mac OS X, you can follow this tutorial.

UIDatePicker timezone fix – Swift iOS

UiDatePicker in Swift has some timezone issues, so we will teach you how you can fix it.

Convert time to different timezones

If you are working on UIDatePicker in your Swift project, you might come across a problem that when fetching the value from UIDatePicker it usually returns the value by mapping with your timezone. But we want to have the actual value from the date picker as it is (without having timezone mapping).

UIDatePicker timezone fix

You can use the following function to get the actual value selected from date picker:

1
datepicker.date.description(with: .current)

Assuming datepicker is your outlet for type UIDatePicker. You can also prevent the user from selecting previous dates by writing the following line at the end of your viewDidLoad() function:

1
2
3
4
5
6
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
     
    datepicker.minimumDate = Date()
}

Video tutorial:

Easy way to save the class object in user defaults – Swift iOS

When it comes to saving the class object in user defaults, there is a hard way to do using NSKeyedArchiver class. But there is an easy to do using JSONEncoder and JSONDecoder classes. In this tutorial, we will teach you how you can:

  1. Save the class object in defaults using Swift by encoding in JSON.
  2. Get a class object from defaults by decoding from JSON.
  3. Remove the class object from defaults.

First, create a model class in Swift which will be the class that needs to be stored in user defaults.

User.swift

1
2
3
4
5
6
import Foundation
 
class User: Codable {
    public var id: Int = 0
    public var name: String = ""
}

Make sure it is a type of Codable protocol, this will help to convert the class into JSON. Set the default values to all data members, integers to 0, and strings to empty string. Then we will create a file which will have all the functions to save, retrieve, and remove the class object value from user defaults, we name that class LocalStorageManager.

LocalStorageManager.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import Foundation
 
class LocalStorageManager {
     
    public func saveUser(user: User) {
        do {
             
            let jsonEncoder = JSONEncoder()
            let jsonData = try jsonEncoder.encode(user)
            let json = String(data: jsonData, encoding: .utf8) ?? "{}"
             
            let defaults: UserDefaults = UserDefaults.standard
            defaults.set(json, forKey: "user")
            defaults.synchronize()
             
        } catch {
            print(error.localizedDescription)
        }
    }
     
    public func getUser() -> User {
        do {
            if (UserDefaults.standard.object(forKey: "user") == nil) {
                return User()
            } else {
                let json = UserDefaults.standard.string(forKey: "user") ?? "{}"
                 
                let jsonDecoder = JSONDecoder()
                guard let jsonData = json.data(using: .utf8) else {
                    return User()
                }
                 
                let user: User = try jsonDecoder.decode(User.self, from: jsonData)
                return user
            }
        } catch {
            print(error.localizedDescription)
        }
        return User()
    }
     
    public func removeUser() {
        let defaults: UserDefaults = UserDefaults.standard
        defaults.removeObject(forKey: "user")
        defaults.synchronize()
    }
}
  1. Create a global data member that will be the key used to identify the object in user defaults.
  2. saveUser function will receive the User class instance as a parameter, convert that as JSON string and save in defaults.
  3. getUser function will return the user class instance by decoding from the JSON string. Here, we will handle all the validations that might be useful for decoding the JSON data.
  4. removeUser function is used to delete the user class instance from defaults.

To use this, we are going to simply call these functions from our main view controller file.

ViewController.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import UIKit
 
class ViewController: UIViewController {
 
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
         
        let user: User = User()
        user.id = 565
        user.name = "Adnan"
         
        LocalStorageManager().saveUser(user: user)
         
        let cacheUser: User = LocalStorageManager().getUser()
        print(cacheUser)
         
        LocalStorageManager().removeUser()
         
        let cacheUserAgain: User = LocalStorageManager().getUser()
        print(cacheUserAgain)
    }
}
  1. First, we are creating an instance of user class and set the values.
  2. Then we are saving in defaults.
  3. After that, we are retrieving the saved user class object and printing it out for debugging.
  4. Finally, we are removing it from defaults and printing it out.

Learn how to do a CRUD operation using local storage in Swift UI

Local storage Swift UI – CRUD