Code:
func mainClassFunction() {
print("mainClassFunction")
}
}
class SubClass: MainClass {
func subClassFunction() {
print("subClassFunction")
}
}
extension SubClass {
override func mainClassFunction() {
print("extension")
}
}
Code:
Dependency injection (DI) is a design pattern in software development that promotes the separation of concerns by allowing components to depend on abstractions rather than concrete implementations. In Swift, dependency injection is commonly used to achieve loosely coupled and easily testable code.
There are three main types of dependency injection:
Constructor Injection: Dependencies are injected through the class's initializer.
Method Injection: Dependencies are injected through methods of the class.
Property Injection: Dependencies are injected through properties of the class.
Let's look at an example using constructor injection in Swift:
// Protocol defining the dependency protocol DataService { func fetchData() -> String } // Concrete implementation of the DataService protocol class RemoteDataService: DataService { func fetchData() -> String { return "Data from remote service" } } // Class that depends on DataService through constructor injection class DataManager { let dataService: DataService init(dataService: DataService) { self.dataService = dataService } func processData() -> String { let data = dataService.fetchData() return "Processed: \(data)" } } // Example of using the DataManager with dependency injection let remoteDataService = RemoteDataService() let dataManager = DataManager(dataService: remoteDataService) let result = dataManager.processData() print(result) // Output: Processed: Data from remote service
In this example:
DataService
is a protocol that defines the contract for fetching data.RemoteDataService
is a concrete implementation of DataService
.DataManager
is a class that depends on DataService
through its initializer.This setup allows you to easily switch the implementation of DataService
without modifying DataManager
. For example, you could create a LocalDataService
implementing DataService
and use it with DataManager
without changing the DataManager
class.
class LocalDataService: DataService { func fetchData() -> String { return "Data from local storage" } } let localDataService = LocalDataService() let dataManagerWithLocalData = DataManager(dataService: localDataService) let resultLocal = dataManagerWithLocalData.processData() print(resultLocal) // Output: Processed: Data from local storage
This flexibility is especially useful for testing, as you can easily substitute real implementations with mock implementations for testing purposes.AI.
Function ending with throw can throw error but normal function can not throw error it can just return value.
Write a closure that accepts string and return length of string(which is integer) :
let simpleClosure:(String) -> (Int) = { name in
return name.count
}
let result = simpleClosure("Hello World")
print(result)
If the last parameter to a function is a closure, Swift lets you use special syntax called trailing closure syntax. Rather than pass in your closure as a parameter, you pass it directly after the function inside braces.
To demonstrate this, here’s our travel() function again. It accepts an action closure so that it can be run between two print() calls:
func travel(action: () -> Void) {
print("I'm getting ready to go.")
action()
print("I arrived!")
}
Because its last parameter is a closure, we can call travel() using trailing closure syntax like this:
travel() {
print("I'm driving in my car")
}
In fact, because there aren’t any other parameters, we can eliminate the parentheses entirely:
travel {
print("I'm driving in my car")
}
Trailing closure syntax is extremely common in Swift, so it’s worth getting used to.
Methods belong to classes, structs, and enums, whereas functions do not.
Methods always belong to a data type, they have a concept of self that functions do not. This is a special value passed in by Swift, and it refers to whatever instance the method was called on.
Swift uses the same keyword, func, for both functions and methods.
Type Method: We can call the method using Struct, Class, or Enum name. The method can be static or Class for making such methods. Static method can not be override but class method can be override.
Instance Method: We can call normal method using making instance of strcut or class. This methods are called instance method.
SWIFT | OBJECTIVE C | |
---|---|---|
Swift is a general-purpose, high-level programming language that is highly concerned about safety, and performance. | Objective C is a general-purpose language that is considered a superset of C language it was designed with the aim of providing object-oriented capabilities. | |
It was developed by Chris Lattner with eventual collaboration with other programmers at Apple. | It was developed by Brad Cox and Tom Love at their company Stepstone. | |
It was influenced by Objective C, Rust, Ruby, and Python. | It was influenced by C and Smalltalk. | |
Swift first appeared on the year 2014. | Objective C first appeared on the year 1984. | |
Swift is a static type. | Objective C is dynamic type. | |
Swift is apache licensed open-source project. | Objective C is licensed under General Public License. | |
It only has classes. | It has both Structs and classes. | |
It was designed for building apps for iOS, Mac, Apple TV, and Apple Watch. | Objective C was designed to be Smalltalk messaging features. | |
Swift polymorphism does not exist directly. | Polymorphism in Objective C exists directly in compile time. | |
It uses true and false values. | It uses YES and NO values and also BOOl. | |
Swift has multiple types of templates than Objective C. | Objective C lacks templates than Swift. |
Key-value observing is the ability for Swift to attach code to variables, so that whenever the variable is changed the code runs. It’s similar to property observers (willSet and didSet ), except KVO is for adding observers outside of the type definition.
KVO isn’t terribly nice in pure Swift code, because it relies on the Objective-C runtime – you need to use @objc classes that inherit from NSObject, then mark each of your properties with @objc dynamic.
For example, we could create a Car class like this:
@objc class Car: NSObject {
@objc dynamic var name = "BMW"
}
let bmw= Car()
You could then observe that user’s name changing like this:
bmw.observe(\Car.name, options: .new) { car, change in
print("I'm now called \(car.name)")
}
That asks BMW to watch for new values coming in, then prints the person’s name as soon as the new value is set.
To try it out, just change the car's name to something else:
bmw.name = "Mercedese"
That will print “I’m now called Mercedese.”
Although KVO is unpleasant in pure Swift code, it’s better when working with Apple’s own APIs – they are all automatically both @objc and dynamic because they are written in Objective-C.
However, one warning: even though large parts of UIKit might work with KVO, this is a coincidence rather than a promise – Apple makes no guarantees about UIKit remaining KVO-compatible in the future.
Compact Map :
Use this method to receive an array of nonoptional values when your transformation produces an optional value.
let scores = ["1", "2", "three", "four", "5"]
let mapped: [Int?] = scores.map { str in Int(str) }
// [1, 2, nil, nil, 5] - Two nil values as "three" and "four" are strings.
let compactMapped: [Int] = scores.compactMap { str in Int(str) }
// [1, 2, 5] - The nil values for "three" and "four" are filtered out.
let scoresByName = ["Henk": [0, 5, 8], "John": [2, 5, 8]]
let mapped = scoresByName.map { $0.value }
// [[0, 5, 8], [2, 5, 8]] - An array of arrays
print(mapped)
let flatMapped = scoresByName.flatMap { $0.value }
// [0, 5, 8, 2, 5, 8] - flattened to only one array
AppUtils.appUtility()
AppUtils.appUtility()
and AppOtherUtils.appUtility()
.static
is same as class final
.appUtility()
anywhere in the project. If you have method with same name as of global function, then access global function with MyAppName.appUtility()
ClassA.appUtility()
and a method named ClassB.appUtility()
, which is useful while developing a library or framework.AppUtility.swift
file and put all the utility functions in it. Later this file can be used across multiple projects.