Skip to content

necatievrenyasar/SwiftTipsTricks

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

13 Commits
Β 
Β 
Β 
Β 

Repository files navigation

Swift tips & tricks πŸš€

Here's some Swift tips & tricks.

Table of contents

#15 Email Validation
#14 Variadic Functions
#13 Failable init
#12 Convenience init
#11 Generic with Where Clause
#10 deinit
#9 compactMap
#8 CustomStringConvertible
#7 Optional Protocol
#6 Unique Array
#5 Defer
#4 Enum rawValues
#3 Enum allCases
#2 For with Where
#1 Optional Chaining

🌜 To check email validation, regex is best way.

extension String {
    var isValidEmail: Bool {
        if self.isEmpty {
            return false
        }
        let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
        let emailPred = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
        return emailPred.evaluate(with: self)
    }
}


print("evren@necatievren.com".isValidEmail)

πŸ‘Ύ Variadic functions takes zero or more input values of a specified type. To work with a variadic function, you just add … after any parameter.

func sum(_ numbers: Double...) -> Double {
    var total: Double = 0
    for number in numbers {
        total += number
    }
    return total
}

print(sum(1, 2, 3, 4, 5))
//15

🐸You can prefer failable initializer for avoid to create object with invalid parameters.

enum AppState{
    case login, register
    
    init?(rawValue:Int) {
        switch rawValue {
        case 0:
            self = .login
        case 1:
            self = .register
        default:
            return nil
        }
    }
}

print(AppState(rawValue: 3))
//nil

πŸ¦‹ convenience init calles designated initializers with pre-set parameters.

class Person {
    var name: String
    var id:Int
    var photo: UIImage
    
    init(name:String, id: Int, photo: UIImage) {
        self.name = name
        self.id = id
        self.photo = photo
    }
    
    convenience init(id: Int) {
        self.init(name: "[Unnamed]", id: id, photo: UIImage(named: "default_photo")!)
    }    
}

πŸ₯½ Where clause help you to filter in values of generic type.

struct Location {
    let lat: Double
    let lon: Double
}
extension Location: CustomDebugStringConvertible {
    var description: String {
        return "Location: \(lat),\(lon)"
    }
}

//Logger is work only class/struct that is extended CustomDebugStringConvertible
struct Logger<T> where T: CustomDebugStringConvertible {
    func debug(ref: T) {
        print(ref)
    }
}

πŸ‘“ deinit function is called before your class is deallocated the memory spaces.deinit function is avaliable only in class type.

class DetailViewController: UIViewController {
  ....

  deinit {
      NotificationCenter.default.removeObserver(self)
   }
}

🐝 compactMap is function like map . That functions applies a transformation to each of elements in a array. However compactMap is automatically removes nil elements from the returned array.

let stringsArray = ["4","5","six","7","ten"]
let intsArray = stringsArray.compactMap {Int($0)}
print(intsArray)
//[4, 5, 7]

🐊 CustomStringConvertible is a protocol that can be implemented on Class and Struct to readable print.

Before

struct Person {
    let firstName: String
    let lastName: String
    let id: Int
    let age: Int
    var fullName: String? = nil
}
let person = Person(firstName: "Ali", lastName: "Tekin", id: 987, age: 20)
print(person)
//Person(firstName: "Ali", lastName: "Tekin", id: 987, age: 20, fullName: nil)

After

struct Person {
    let firstName: String
    let lastName: String
    let id: Int
    let age: Int
    var fullName: String? = nil
}

extension Person: CustomStringConvertible {
    var description: String {
        return "Person: \(firstName) \(lastName) id: \(id)"
    }
}
let person = Person(firstName: "Ali", lastName: "Tekin", id: 987, age: 20)
print(person)
//Person: Ali Tekin id: 987

🦁 Swift does not allow us to perform optional functions. We can do it through extension

protocol DetailVMDelegate:class {
    func detailVM(_ viewModel: DetailVM, data: [String])
    func detailVMShowPreloader(_ viewModel: DetailVM, status: Bool)
}

extension DetailVMDelegate {
    func detailVMShowPreloader(_ viewModel: DetailVM, status: Bool) {}
}

🦿 If you want removing duplicate item from an array, there are several ways but I prefer to use set

let values = [1,2,3,4,4,4,5,6,7]
let valuesSet = Set(values)
let uniqueValues = Array(valuesSet)

🦿 defer statement is the last block of code that will be executed in function.

func doSometing() {
  defer {print ("First")}
  defer {print ("Second")}
  print("End of function")
}
//End of function
//First
//Second

Most common usage:

func readFile(_ name:String) {
  	let manager: FileManager? = FileManager(with: name) 
  	defer {
      	manager.?closeFile()
    }
  	....
}

πŸŽƒ You can access cases of enum directly by use a rawValue

enum City:Int {
    case adana
    case adiyaman
    case afyon
    case agri
    case amasya
    case ankara
}
//Index start by 0.
let city06 = City.init(rawValue: 06 - 1)

🧣 If you want to access all cases of enum, you must enable CaseIterable protocol.

enum Direction: CaseIterable {
    case north, south, east, west
}

for item in Direction.allCases {
  	...
}

🐨 More safety and fast then 'if break'

Before

for player in game.players {
    if player.id == currentId {
        ...
        break
    }
}

After

for player in game.players where player.id == currentId {
    ...
}

❓ Optional Chaining that is really cool property in Swift, is help you to avoid 'If blogs'

Before

if let place = placeModel {
    if let reviews = place.reviews {
        if let firstReview = reviews.first? {
            ...
        }
    }
}

After

guard let firstReview = placeModel?.reviews?.first? else {return}
...

Releases

No releases published

Packages

No packages published