Here's some Swift tips & tricks.
#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}
...