awesome-ios-developer/README.md

845 lines
26 KiB
Markdown
Raw Normal View History

2021-04-10 16:21:15 +07:00
# Useful Swift Things
2021-04-10 15:42:23 +07:00
2021-04-10 16:27:15 +07:00
<div align="center">
2021-04-13 13:32:42 +07:00
<img src="https://github.com/jphong1111/Useful_Swift/blob/main/Images/swift.jpeg">
2021-04-10 16:27:15 +07:00
</div>
2021-04-27 12:19:44 +07:00
<p>
</p>
2021-04-27 12:11:04 +07:00
<p align="center">
<img src="https://img.shields.io/badge/-OneDayOneCommit-critical?style=plastic&logo=swift" />
2021-05-25 17:49:21 +07:00
![visitors](https://page-views.glitch.me/badge?page_id=jphong1111.Useful_Swift)
2021-04-27 12:11:04 +07:00
</p>
2021-04-13 13:33:49 +07:00
2021-05-24 10:35:26 +07:00
**Feel free to fork this repository and pull requests!**
2021-04-10 16:15:30 +07:00
## Content
2021-05-23 11:34:45 +07:00
- [Coding Convention](#Coding-convention)
2021-05-05 15:26:00 +07:00
- [Swift Lint](#Swift-lint)
2021-04-10 16:05:27 +07:00
- [Design Pattern](#Design-Pattern)
2021-05-24 03:31:51 +07:00
- [Delegation](#Delegation)
2021-04-11 02:05:11 +07:00
- [Singleton](#Singleton)
2021-05-24 03:31:51 +07:00
- [Observer](#Observer)
2021-05-24 13:50:36 +07:00
- [Code Structuring](#code-structuringarchitecture)
2021-04-10 16:20:15 +07:00
- [MVC](#MVC)
- [MVVM](#MVVM)
2021-04-27 11:39:33 +07:00
- [VIPER](#VIPER)
2021-04-10 04:19:52 +07:00
- [UIDesign](#UIDesign)
2021-04-22 17:06:56 +07:00
- [Helper](#Helper)
2021-05-03 14:35:24 +07:00
- [Email, Message, Call](#email-message-call)
2021-05-03 13:57:35 +07:00
- [Network Layer](#Network-Layer)
2021-05-03 16:50:11 +07:00
- [Image Picker](#Image-Picker)
2021-05-03 18:21:44 +07:00
- [File Manager](#File-Manager)
- [Video Downloader](#Video-Downloader)
2021-05-20 10:50:21 +07:00
- [Image Downloader](#Image-Downloader)
2021-05-03 19:09:09 +07:00
- [Location Manager](#Location-Manager)
2021-04-10 04:19:52 +07:00
- [API](#API)
2021-04-10 15:55:09 +07:00
- [JSON](#JSON)
2021-05-23 11:39:07 +07:00
- [UserDefaults](#UserDefaults)
2021-05-22 01:00:30 +07:00
- [How to find documentDirectory](#How-to-find-documentDirectory)
2021-05-22 00:55:41 +07:00
- [Core Data](#Core-Data)
2021-05-24 08:20:37 +07:00
- [Set Up Core Data](#Set-Up-Core-Data)
2021-05-25 01:01:12 +07:00
- [Usage](#Usage)
- [Store Data](#Store-Data)
2021-05-25 03:02:19 +07:00
- [Load Data](#Load-Data)
2021-05-25 04:14:07 +07:00
- [Update Data](#Update-Data)
- [Delete Data](#Delete-Data)
2021-04-10 04:30:48 +07:00
- [Third Party Library](#Third-Party-Library)
2021-04-29 11:42:01 +07:00
- [GCD](#GCD)
2021-04-30 13:40:48 +07:00
- [DispatchQueue](#DispatchQueue)
- [DispatchGroup](#DispatchGroup)
- [DispatchWorkItem](#DispatchWorkItem)
2021-04-30 17:16:16 +07:00
- [Thread Sanitizer](#Thread-Sanitizer)
2021-05-07 15:10:24 +07:00
- [Testing](#Testing)
2021-05-14 17:33:02 +07:00
- [Code Coverage](#Code-Coverage)
2021-05-07 15:10:24 +07:00
- [Unit Test](#Unit-Test)
- [UI Test](#UI-Test)
2021-05-25 03:02:19 +07:00
- [In App Purchase(IAP)](#In-App-PurchaseIAP)
2021-05-21 10:16:54 +07:00
- [APNS](#APNS)
2021-05-21 10:55:16 +07:00
- [FRP](#FRP)
2021-05-24 03:37:34 +07:00
- [Error Search](#Error-Search)
2021-04-23 14:19:47 +07:00
- [Useful Stuff](#Useful-Stuff)
2021-04-23 23:34:04 +07:00
- [Show Preview in UIKit(Build UI with Code Base)](#show-preview-in-uikitbuild-ui-with-code-base-----)
2021-04-25 04:50:50 +07:00
- [Write README.md](#write-readmemd)
2021-05-21 10:55:16 +07:00
- [Roadmap for iOS Developer](#Roadmap-for-iOS-Developer)
2021-04-10 03:16:44 +07:00
2021-04-10 03:25:46 +07:00
2021-04-10 04:13:06 +07:00
## Coding convention
2021-04-10 15:22:54 +07:00
set of guidelines for a specific programming language that recommend programming style
### Swift Style Guide
2021-04-10 04:12:26 +07:00
2021-04-10 14:51:46 +07:00
- [Swift Style Guide](https://github.com/linkedin/swift-style-guide)
2021-04-10 04:34:45 +07:00
### Swift Lint
2021-04-10 15:20:40 +07:00
The way of force you to adapt coding convention
>otherwise project build will **FAILED**
2021-04-10 15:14:13 +07:00
- [Swift Lint](https://github.com/realm/SwiftLint) apply for all project:+1:
2021-04-15 19:36:44 +07:00
```swift
2021-04-15 19:36:01 +07:00
if which swiftlint >/dev/null; then
swiftlint
else
echo "error: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
exit 1
fi
```
2021-04-10 04:34:45 +07:00
put .yml file into root folder and apply following code in Build Phases
2021-04-10 03:47:49 +07:00
2021-04-22 17:19:49 +07:00
**You can modify(delete) SwiftLint Option with opening .yml file**
2021-04-22 17:20:10 +07:00
2021-04-22 17:21:49 +07:00
> Shift + Command + . will show the hidden file
2021-04-22 17:19:49 +07:00
<img src="https://github.com/jphong1111/Useful_Swift/blob/main/Images/swiftLintChange.png">
2021-04-10 16:11:11 +07:00
## Design Pattern
2021-04-14 04:00:57 +07:00
Design pattern is
2021-04-14 04:01:22 +07:00
2021-04-14 04:00:57 +07:00
Check [this](https://refactoring.guru/design-patterns/swift) website for design pattern in Swift
2021-04-10 16:11:11 +07:00
2021-05-24 03:31:51 +07:00
### Delegation
2021-04-10 16:11:11 +07:00
2021-04-10 16:30:44 +07:00
```swift
2021-04-10 16:11:11 +07:00
weak var delegate: SomeProtocol?
```
2021-05-24 03:31:51 +07:00
### Singleton
2021-04-10 16:11:11 +07:00
2021-04-10 16:30:44 +07:00
```swift
2021-04-10 16:11:11 +07:00
class SingletonPattern {
static let manager = SingletonPattern()
private init() {}
2021-04-10 16:11:45 +07:00
}
2021-04-10 16:11:11 +07:00
```
2021-04-14 04:02:14 +07:00
2021-05-24 03:31:51 +07:00
### Observer
2021-04-14 04:02:14 +07:00
2021-05-06 20:56:57 +07:00
The observer pattern lets one object observe changes on another object. Apple added language-level support for this pattern in Swift 5.1 with the addition of Publisher in the Combine framework.
2021-05-10 02:48:29 +07:00
<img src = "https://github.com/jphong1111/Useful_Swift/blob/main/Images/observer.png" />
2021-04-14 04:02:14 +07:00
2021-05-24 13:48:45 +07:00
## Code Structuring(Architecture)
2021-04-10 16:05:27 +07:00
2021-04-10 16:18:23 +07:00
### MVC
2021-04-10 16:05:27 +07:00
2021-05-24 13:48:45 +07:00
MVC pattern stands for Model - View - Controller
2021-04-15 10:00:46 +07:00
<img src="https://github.com/jphong1111/Useful_Swift/blob/main/Images/MVCModel.png">
2021-04-13 13:33:49 +07:00
2021-05-24 13:48:45 +07:00
- Model - Model take care of storing data.
- View - View renders the data for users
- Controller - Controller modifies the View, accepts user input and interacts directly with the Model. And take care of view logic and business logic.
2021-04-10 16:20:15 +07:00
### MVVM
2021-05-24 13:48:45 +07:00
MVVM patterns stand for Model - View - ViewModel
2021-04-15 10:01:10 +07:00
##### MVC vs MVVM
2021-04-15 10:00:46 +07:00
2021-05-24 13:48:45 +07:00
<img src="https://github.com/jphong1111/Useful_Swift/blob/main/Images/MVVMvsMVC.png" width = "60%" height = "60%">
2021-04-15 10:00:46 +07:00
2021-05-24 13:52:46 +07:00
- Model Which holds the application data
2021-04-19 15:39:24 +07:00
2021-05-24 13:52:46 +07:00
- View It displays the data that is stored in model. These are visual elements through which a user interacts. These are subclasses of UIView
2021-04-19 15:39:24 +07:00
2021-05-24 13:52:46 +07:00
- View Model Transform model information/data and it interacts with controller or view to display those informations.
2021-04-19 15:39:24 +07:00
2021-05-24 13:52:46 +07:00
- Controller class It will be there but the responsibility of view business logic has been removed and give to view model
2021-04-19 15:39:24 +07:00
2021-05-24 13:48:45 +07:00
> You can check App example of using MVVM [here](https://github.com/jphong1111/Unsplash_Clone)
2021-04-19 15:39:24 +07:00
2021-04-27 11:39:33 +07:00
### VIPER
2021-05-24 13:50:36 +07:00
<img src="https://github.com/jphong1111/Useful_Swift/blob/main/Images/Viper.png">
2021-05-24 13:48:45 +07:00
- View - Displays what it is told to by the Presenter and relays user input back to the Presenter.
- Interactor - Contains the business logic as specified by a use case.
- Presenter - contains view logic for preparing content for display (as received from the Interactor) and for reacting to user inputs (by requesting new data from the Interactor).
- Entity - contains basic model objects used by the Interactor.
- Routing - contains navigation logic for describing which screens are shown in which order.
2021-05-24 13:52:46 +07:00
> For more info, go [here](https://www.raywenderlich.com/8440907-getting-started-with-the-viper-architecture-pattern)
2021-04-10 04:13:06 +07:00
## UIDesign
2021-04-10 03:58:50 +07:00
2021-04-10 04:16:24 +07:00
### HIG(Human Interface Guidelines)
2021-04-10 14:51:46 +07:00
- [Apple UI Kit](https://developer.apple.com/documentation/uikit)
2021-05-03 10:58:56 +07:00
- [iOS Design Guide](https://ivomynttinen.com/blog/ios-design-guidelines)
2021-04-10 04:16:24 +07:00
2021-04-10 04:13:06 +07:00
### iOS icon
2021-05-24 14:01:26 +07:00
- [SF Symbols](https://developer.apple.com/sf-symbols/) Download SF Symbols2 for more icons!
2021-05-05 17:35:44 +07:00
- [icon8](https://icons8.com/) You can download icons imge for your **APP**
2021-05-05 17:36:18 +07:00
- [appicon](https://appicon.co/) generate the app icon size
2021-04-10 03:58:50 +07:00
2021-04-10 04:13:06 +07:00
### UIdesign inspiration
2021-04-10 03:58:50 +07:00
2021-04-10 04:33:17 +07:00
- [dribble](https://dribbble.com/)
- [pinterest](https://pinterest.com/)
- [behance](https://www.behance.net/)
- [pttrns](https://pttrns.com/)
- [awwwards](https://www.awwwards.com/)
- [flickr](http://www.flickr.com/)
- [mobbin](https://mobbin.design/)
## Helper
2021-04-22 17:06:56 +07:00
2021-05-03 13:57:35 +07:00
All files are resuable files and protocol oriented. **Just Copy and Paste inside your project and use it!!** 👍
2021-05-03 16:51:46 +07:00
## Email, Message, Call
2021-05-03 13:57:35 +07:00
2021-04-22 17:06:56 +07:00
You can check the file in the follow link
- [Email, Message, Call](https://github.com/jphong1111/Useful_Swift/blob/main/Helper/ConversationManager.swift)
2021-05-03 18:21:44 +07:00
### Usage
2021-05-24 23:30:30 +07:00
import MessageUI first
2021-04-22 17:14:29 +07:00
```swift
import MessageUI
```
Then use it
2021-05-03 18:29:22 +07:00
> Don't forget to extend the mail, message delegate to your ViewController!
2021-04-22 17:14:29 +07:00
```swift
2021-05-03 18:29:22 +07:00
lazy var conversation = ConversationManager(presentingController: self, mailDelegate: self, messageDelegate: self, viewController: self)
2021-05-03 18:29:22 +07:00
@IBAction private func sendEmail(_ sender: UIButton) {
conversation.sendEmail(feedback: MailFeedback(recipients: ["abcd@google.com"], subject: "FeedBack", body: "Write feedback here"))
}
2021-05-03 18:29:22 +07:00
@IBAction private func sendMessage(_ sender: UIButton) {
conversation.sendMessage(feedback: MessageFeedBack(recipients: ["1111111111"], body: "Type here"))
}
2021-05-03 18:29:22 +07:00
@IBAction private func startCall(_ sender: UIButton) {
conversation.makeCall(number: "1111111111")
}
```
2021-04-10 03:58:50 +07:00
2021-05-03 18:41:57 +07:00
Good To GO 👏👏👏
> See Example [here](https://github.com/jphong1111/ImageMessageHandler_DemoApp)
2021-05-03 16:51:46 +07:00
## Network Layer
2021-05-03 13:57:35 +07:00
2021-05-03 13:58:22 +07:00
- [Network Layer](https://github.com/jphong1111/Useful_Swift/tree/main/Helper/Network%20Layer)
2021-05-03 13:57:35 +07:00
2021-05-03 16:51:46 +07:00
### Usage
2021-05-03 14:26:28 +07:00
First, set the base URL in **EndPointType file**
2021-05-03 17:05:30 +07:00
> Don't forget to put your API key in it!
2021-05-03 14:26:28 +07:00
```swift
var baseURL: URL {
guard let url = URL(string: "https://api.openweathermap.org/data/2.5/") else {
fatalError("baseURL could not be configured.")
}
return url
}
```
then make a instance of router.swift file in your code
```swift
private let router = Router<YourAPI>()
```
2021-05-03 14:27:54 +07:00
for **YourAPI part**, simply create a new **enum** with cases about specific api URL
2021-05-03 14:26:28 +07:00
> It will make your router more dynamic!
> Don't forget extension to EndPointType!
```swift
enum YourAPI {
case first(country: String)
case second(time: Int)
case third(name: String)
}
extension YourAPI: EndPointType {
var path: String {
switch self {
case .first(let country):
return "\(country).json"
case .second(let time):
return "\(time).json"
2021-05-03 14:27:54 +07:00
case .third(let name):
2021-05-03 14:26:28 +07:00
return "\(name).json"
}
}
}
```
then, use it like this
```swift
router.request(.first(country: London)) { [weak self] (results: Result<CountryWeather, AppError>) in
guard let self = self else { return }
switch results {
case .success(let data):
// insert your modifications!
case .failure(let error):
// insert your modifications!
print(error)
}
}
```
> **CountryWeather should be a model with Decodable**
2021-05-20 10:42:57 +07:00
If you want to see how can I use Network Layer in Project, check [this](https://github.com/jphong1111/Unsplash_Clone/tree/main/Unsplah_Clone/ReusableComponent/NetworkLayer)
2021-05-03 14:26:28 +07:00
2021-05-03 14:29:43 +07:00
This reusable network layer files for referenced from [here](https://medium.com/flawless-app-stories/writing-network-layer-in-swift-protocol-oriented-approach-4fa40ef1f908)
2021-05-20 10:42:57 +07:00
> Also [Alamofire](https://github.com/Alamofire/Alamofire) will be a great option for Network Layer!
2021-05-03 16:51:46 +07:00
## Image Picker
2021-05-03 16:50:11 +07:00
2021-05-06 00:51:33 +07:00
- [Image Picker](https://github.com/jphong1111/Useful_Swift/blob/main/Helper/ImagePickerHandler/ImagePicker.swift)
2021-05-03 16:50:11 +07:00
2021-05-03 16:51:46 +07:00
### Usage
2021-05-03 16:50:11 +07:00
Copy and Paste in your project and then declare Image Picker object inside your project
```swift
lazy var imagePicker = ImagePicker(presentationController: self, delegate: self)
```
Then, extend ImagePickerDelegate to your viewController
```swift
extension ViewController: ImagePickerDelegate {
func didSelect(image: UIImage?) {
self.yourImageView.image = image
self.dismiss(animated: true, completion: nil)
}
}
```
Good To GO 👏👏👏
> See Example [here](https://github.com/jphong1111/ImageMessageHandler_DemoApp)
2021-05-03 18:21:44 +07:00
## File Manager
2021-05-03 18:46:08 +07:00
- [File Manager](https://github.com/jphong1111/Useful_Swift/blob/main/Helper/FileManageHelper.swift)
### Usage
Copy and Paste in your project
```swift
let readData = FileManageHelper.manager.readFile(filename: fileNameTextField.text ?? "", type: extensionTextField.text ?? "")
resultTextField.text = readData
```
> File Manager are wrote with singleton pattern, therefore no need to declare in side your code!
2021-05-03 18:21:44 +07:00
2021-05-03 18:51:05 +07:00
Good To GO 👏👏👏
2021-05-03 18:21:44 +07:00
## Video Downloader
2021-05-03 18:51:05 +07:00
- [Video Downloader](https://github.com/jphong1111/Useful_Swift/blob/main/Helper/VideoManager.swift)
## Usage
Make an object of VideoManager inside your code
```swift
let videoManager = VideoManager()
```
use downloadVideoLinkAndCreateAsset function to start download with entering URL
```swift
self.videoManager.downloadVideoLinkAndCreateAsset(text)
```
Good To GO 👏👏👏
2021-05-03 18:21:44 +07:00
2021-05-20 10:50:21 +07:00
## Image Downloader
There is no file for Image Downloader.
To download images into device, only thing is this
```swift
if let data = try? Data(contentsOf: urls),
let image = UIImage(data: data) {
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
}
```
2021-05-20 10:52:34 +07:00
Just **change urls into your image URL**
2021-05-20 10:50:21 +07:00
> UIImageWriteToSavedPhotosAlbum will take care it to download to device.
2021-05-20 10:52:34 +07:00
2021-05-20 10:50:21 +07:00
> For more info go [here](https://www.hackingwithswift.com/example-code/media/uiimagewritetosavedphotosalbum-how-to-write-to-the-ios-photo-album)
Good To GO 👏👏👏
2021-05-03 19:09:09 +07:00
## Location Manager
2021-05-24 23:44:45 +07:00
- ~~[Location Manager](https://github.com/jphong1111/Useful_Swift/tree/main/Helper/LocationHandler/LocationManager.swift)~~
Currently Working
2021-05-03 19:09:09 +07:00
2021-04-10 04:13:06 +07:00
## API
2021-04-10 04:12:26 +07:00
2021-05-01 09:20:43 +07:00
API(Application Programming Interface) is an interface that defines interactions between multiple software applications or mixed hardware-software intermediaries. It defines the kinds of calls or requests that can be made, how to make them, the data formats that should be used, the conventions to follow, etc.
2021-04-10 04:30:48 +07:00
2021-04-10 15:55:09 +07:00
## JSON
2021-04-10 15:58:08 +07:00
JSON is a language-independent data format
2021-04-10 16:01:31 +07:00
> Which is relative with **KEY - VALUE** pair
2021-04-10 16:30:44 +07:00
```json
2021-04-10 15:58:08 +07:00
{
2021-04-10 16:00:40 +07:00
"main": [
2021-04-10 15:58:08 +07:00
{
2021-04-10 16:00:40 +07:00
"title": "example1",
2021-04-10 16:31:31 +07:00
"body": "body1"
2021-04-10 15:58:08 +07:00
},
{
2021-04-10 16:00:40 +07:00
"title": "example2",
2021-04-10 16:31:31 +07:00
"body: "body2"
2021-04-25 04:53:10 +07:00
}
2021-04-10 15:58:08 +07:00
]
}
2021-04-10 16:00:40 +07:00
```
2021-04-10 15:55:09 +07:00
### JSON parser extension for Chrome
2021-04-10 16:05:27 +07:00
This extension makes JSON more structable
2021-04-10 15:55:09 +07:00
[JSON parser pro](https://chrome.google.com/webstore/detail/json-viewer-pro/eifflpmocdbdmepbjaopkkhbfmdgijcc) **FREE** :+1:
2021-04-10 16:15:30 +07:00
### JSON Decoding
2021-05-01 09:20:43 +07:00
To use JSON Decoding in swift, you have to define the model to be Codable or Decodable
```swift
public typealias Codable = Decodable & Encodable
```
> Decodable can only decode the json data. Can't encoded json file!!
```swift
struct User: Codable {
var first_name: String
var last_name: String
var country: String
}
```
2021-05-20 10:34:45 +07:00
To use JSONDecoding, declare JSONDecoder and use decode() function
```swift
do {
let data = try JSONDecoder().decode(T.self, from: unwrappedData)
completionOnMain(.success(data))
} catch {
print(error)
completionOnMain(.failure(.parseError))
}
```
T.self -> Model(Struct) of the data that you want to decode
> data will decoded to form of T
unwrappedData -> Input actual data from file or server
> This should be a Data Type!!
2021-04-10 16:15:30 +07:00
### JSONSerialization
2021-05-24 08:22:30 +07:00
JSONSerialization is a old way of decode the JSON file
### Various API Site
- [rapidAPI](https://www.rapidapi.com)
2021-05-22 00:55:41 +07:00
2021-05-23 11:39:07 +07:00
## UserDefaults
2021-05-22 00:55:41 +07:00
The UserDefaults class provides a programmatic interface for interacting with the defaults system. Check [Apple Document](https://developer.apple.com/documentation/foundation/userdefaults) for more info
2021-05-23 11:39:07 +07:00
> UserDefaults has to have **key-value** pair
2021-05-22 00:55:41 +07:00
2021-05-23 11:39:07 +07:00
### When do we use UserDafaults
- User information, like name, email address, age, occupation
- App settings, like user interface language, app color theme or “detailed vs. simple UI”
- Flags, more on this later
2021-05-24 03:20:42 +07:00
- If store data is small
2021-05-22 00:55:41 +07:00
### How to find documentDirectory
Put this line of code inside of your project
```swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
print(NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).last ?? "")
return true
}
```
2021-05-22 03:50:22 +07:00
<img src = "https://github.com/jphong1111/Useful_Swift/blob/main/Images/DocumentPath.png" />
2021-05-22 00:55:41 +07:00
simply move into that path and you can find the documentDirectory of your Application
> if Library is not shown up, just do **Shift + Command + .** to show hidden files in your folder
2021-05-22 03:50:22 +07:00
<img src = "https://github.com/jphong1111/Useful_Swift/blob/main/Images/UserDefaultPlistPath.png" />
2021-05-22 03:53:03 +07:00
### Usage
2021-05-22 03:27:41 +07:00
As you can see in the below, intArray will stored inside the device through UserDefaults(), so that if device is shut down, changed value wil be stored in device.
```swift
class ViewController: UIViewController {
var intArray = [1,2,3,4,5]
let defaults = UserDefaults()
override func viewDidLoad() {
super.viewDidLoad()
intArray = defaults.array(forKey: "IntArray") as! [Int]
}
@IBOutlet weak var textField: UILabel!
@IBAction private func isClicked(_ sender: UIButton) {
intArray.append(6)
defaults.set(intArray, forKey: "IntArray")
textField.text = "\(intArray)"
}
}
```
2021-05-22 03:50:22 +07:00
You can your plist file like this!
<img src = "https://github.com/jphong1111/Useful_Swift/blob/main/Images/UserDefaultPlist.png" />
2021-05-24 03:20:42 +07:00
Declare Userdefault like this!
```swift
let defaults = UserDefaults.standard
```
> **standard** allows to access from anywhere inside device
2021-05-24 03:29:08 +07:00
**With using set function, you can set userdefaults**
2021-05-24 03:20:42 +07:00
2021-05-24 03:27:53 +07:00
<img src = "https://github.com/jphong1111/Useful_Swift/blob/main/Images/UserDefaultSet.png" width = "60%" height = "60%"/>
2021-05-24 03:20:42 +07:00
2021-05-24 03:29:08 +07:00
**Also these function will allow to get a data from plist**
2021-05-24 03:20:42 +07:00
2021-05-24 03:27:53 +07:00
<img src = "https://github.com/jphong1111/Useful_Swift/blob/main/Images/UserDefaultGet.png" width = "60%" height = "60%"/>
2021-05-24 03:20:42 +07:00
2021-05-22 03:50:22 +07:00
**You are GOOD TO GO** 👏👏👏
2021-05-22 03:27:41 +07:00
2021-05-22 00:55:41 +07:00
## Core Data
2021-05-24 08:26:38 +07:00
Use Core Data to save your applications permanent data for offline use, to cache temporary data, and to add undo functionality to your app on a single device.
2021-05-25 01:01:12 +07:00
**Core Data in Swift is using SQLite as DEFAULT**
2021-05-24 04:42:55 +07:00
<img src = "https://github.com/jphong1111/Useful_Swift/blob/main/Images/DataStoreInSwift.png" width = "50%" height = "50%"/>
2021-05-24 04:44:18 +07:00
> Image From London App Brewery
2021-05-22 00:55:41 +07:00
2021-05-24 08:20:37 +07:00
### Set Up Core Data
Simply Click Core Data check box when you create a new project
2021-05-24 08:26:38 +07:00
<img src = "https://github.com/jphong1111/Useful_Swift/blob/main/Images/AddCoreData.png" width = "50%" height = "50%"/>
2021-05-24 08:20:37 +07:00
If you want to attach Core Data in exsiting project
Create **Data Model** file first
2021-05-24 08:26:38 +07:00
<img src = "https://github.com/jphong1111/Useful_Swift/blob/main/Images/AddDataModel.png" width = "50%" height = "50%"/>
2021-05-24 08:20:37 +07:00
Then import CoreData inside your **AppDelegate.swift** file
```swift
import CoreData
```
And Copy and Paste this lines of code inside your **AppDelegate.swift** file
```swift
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentContainer(name: "Your DataModel file name")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
// MARK: - Core Data Saving support
func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
```
Don't forget to change it
```swift
let container = NSPersistentContainer(name: "Your DataModel file name")
```
And goto **SceneDelegate.swift** file, copy below lines of code and replace yours
```swift
func sceneDidEnterBackground(_ scene: UIScene) {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
// Save changes in the application's managed object context when the application transitions to the background.
(UIApplication.shared.delegate as? AppDelegate)?.saveContext()
}
```
2021-05-24 08:51:20 +07:00
If your target is **below iOS13**, put this line of code in side your **applicationWillTerminate** of **AppDelegate.swift** file
2021-05-24 08:20:37 +07:00
```swift
self.saveContext()
```
2021-05-24 10:02:52 +07:00
## Usage
Once you create your DataModel file, you can simply create a **Entity(Class)** and **Attributes(Properties)**
And then, change the type of attributes in inspector like this
2021-05-24 12:19:06 +07:00
<img src = "https://github.com/jphong1111/Useful_Swift/blob/main/Images/DataModelAttribute_inspector.png"/>
Once you create your own Entities & Attributes, go to Inspector and change Module to **CurrentProductModule**
<img src = "https://github.com/jphong1111/Useful_Swift/blob/main/Images/DataModelAttributes.png"/>
> If you didn't set it, thats fine, but if you are working in big project, then you need to set it. Otherwise this can occurs some error.
2021-05-24 10:02:52 +07:00
2021-05-24 12:36:31 +07:00
#### Codegen
As you can see in above, there are three options
- Manual/None - Swift didn't generate CoreDataClass, CoreDataProperties files so that you have to create yourself **(full control)**
- Class Definition - Swift will generate CoreDataClass, CoreDataProperties files. **(No control)**
- Category/Extension - Swift will generate only Extension file **(Some Control)**
2021-05-24 10:02:52 +07:00
CoreDataClass, CoreDataProperties are located in below
2021-05-24 12:37:17 +07:00
> /Users/dennis/Library/Developer/Xcode/DerivedData/CoreDataUserDefaultPractice-hisefjfyuvglrjekndpftwazftug/Build/Intermediates.noindex/CoreDataUserDefaultPractice.build/Debug-iphonesimulator/CoreDataUserDefaultPractice.build/DerivedSources/CoreDataGenerated/CoreDataUserDefaultPractice
2021-05-24 10:02:52 +07:00
2021-05-24 12:36:31 +07:00
And CoreDataClass, CoreDataProperties are looking like this,
2021-05-24 12:19:06 +07:00
<img src = "https://github.com/jphong1111/Useful_Swift/blob/main/Images/CoreDataClass_Properties.png"/>
2021-05-24 23:45:54 +07:00
2021-05-24 23:44:45 +07:00
> If your code can run it but didn't get your Entities, **Rebuild it or Restart your Xcode**
2021-05-24 10:02:52 +07:00
2021-05-25 01:01:12 +07:00
## Store Data
Declare context as a global variable
```swift
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
```
> Get viewContext that we defined in AppDelegate.swift file
Simply you can use this code to save your data to CoreData
```swift
func saveItem() {
do {
try context.save()
} catch {
print("Error Saving Context: \(error.localizedDescription)")
}
}
```
> Use it wherever you want
Data can be find if you print the path
```swift
print(FileManager.default.urls(for: .documentDirectory, in: .userDomainMask))
```
<img src = "https://github.com/jphong1111/Useful_Swift/blob/main/Images/CoreDataSQLite.png" />
2021-05-25 01:02:28 +07:00
2021-05-25 01:01:12 +07:00
> You can check Entities, Properties inside that file
2021-05-25 03:02:19 +07:00
## Load Data
Refer this code and apply it to your code wherever you want to reload it
```swift
func loadItem() {
let request: NSFetchRequest<Item> = Item.fetchRequest()
do {
itemArray = try context.fetch(request)
} catch {
print("Load Item Error: \(error.localizedDescription)")
}
}
```
> Item will be your Entity, itemArray will be your Entity object
> Don't forget to import **CoreData**
2021-05-25 04:14:07 +07:00
## Update Data
Simply use setValue function so that you can update your value in DB
```swift
itemArray[0].setValue(<#T##value: Any?##Any?#>, forKey: <#T##String#>)
```
> if you are using TableView or CollectionView, change 0 to indexPath.row
## Delete Data
Simply use delete function in context
```swift
context.delete(itemArray[0])
```
> change number for dynamic!
2021-05-24 08:20:37 +07:00
**You are GOOD TO GO** 👏👏👏
2021-05-07 15:10:24 +07:00
## Third Party Library
[This github](https://github.com/vsouza/awesome-ios) contains all the popular libraries in Swift:+1:
2021-05-21 10:10:28 +07:00
Recommand Useful Library
2021-05-25 03:02:19 +07:00
- SDWebImage - Download and set image Library
- Hero - Various kind of animation with using Segue
- Alamofire - Network Layer tool
- RxSwift - Reactive Programming in Swift
2021-05-21 10:10:28 +07:00
2021-04-29 11:42:01 +07:00
## GCD
GCD(Grand Central Dispatch) is a low-level API for managing concurrent operations. It can help you improve your apps responsiveness by deferring computationally expensive tasks to the background.
2021-04-10 16:15:30 +07:00
2021-04-30 13:40:48 +07:00
### DispatchQueue
2021-04-30 14:06:31 +07:00
An object that manages the execution of tasks serially or concurrently on your app's main thread or on a background thread.
2021-04-30 13:40:48 +07:00
#### main
2021-04-30 14:06:31 +07:00
We can say main is a serial queue
2021-04-30 13:40:48 +07:00
#### global()
2021-04-30 14:06:31 +07:00
We can say global is a concurrent queue
2021-04-30 13:40:48 +07:00
### DispatchGroup
### DispatchWorkItem
2021-04-30 17:16:16 +07:00
### Thread Sanitizer
Thread Sanitizer is a tool to identifies the potential thread-related corruption issues. And it is a good way to find the [Readers and Writers problem](https://en.wikipedia.org/wiki/Readers%E2%80%93writers_problem) in your application.
2021-04-30 13:58:38 +07:00
#### How to Use Address Sanitizer
Go to this Option and Click **EDIT SCHEME...** 👈
2021-04-30 14:01:13 +07:00
<img src="https://github.com/jphong1111/Useful_Swift/blob/main/Images/address_sanitizer.png">
2021-04-30 17:16:16 +07:00
And then go to **RUN** and check **THREAD SANITIZER** 👈
2021-04-30 13:58:38 +07:00
2021-04-30 17:18:31 +07:00
<img src="https://github.com/jphong1111/Useful_Swift/blob/main/Images/thread_sanitizer.png">
2021-04-30 13:40:48 +07:00
2021-05-07 15:10:24 +07:00
## Testing
2021-05-14 17:30:52 +07:00
Before start your Testing, add coverage will be a good option to show the result of test
2021-05-14 17:33:02 +07:00
### Code Coverage
First, check code coverage
2021-05-14 17:30:52 +07:00
<img src ="https://github.com/jphong1111/Useful_Swift/blob/main/Images/addCoverage1.png" />
2021-05-14 17:33:02 +07:00
Then, go to **EDIT SHEME**, check like this
2021-05-14 17:30:52 +07:00
<img src ="https://github.com/jphong1111/Useful_Swift/blob/main/Images/addCoverage2.png" />
2021-05-07 15:10:24 +07:00
### Unit Test
### UI Test
2021-04-23 14:19:47 +07:00
2021-05-25 03:02:19 +07:00
## In App Purchase(IAP)
2021-05-21 10:16:54 +07:00
IAP stands for **In App Purchase**
## APNS
APNS stands for **Apple Push Notification service**
2021-05-21 10:55:16 +07:00
## FRP
Functional Reactive Programming a.k.a [RxSwift](https://github.com/ReactiveX/RxSwift)
2021-05-21 10:16:54 +07:00
2021-05-24 03:37:34 +07:00
## Error Search
2021-05-24 03:52:46 +07:00
Find your common error here
[Error Search](https://github.com/jphong1111/Useful_Swift/blob/error-search/README.md)
2021-05-24 03:37:34 +07:00
2021-04-23 14:19:47 +07:00
## Useful Stuff
2021-04-23 14:25:02 +07:00
### Show Preview in UIKit(Build UI with Code Base) 👍 👍 👍 👍 👍
Copy this code and Paste into your controller
2021-04-23 14:19:47 +07:00
```swift
2021-05-05 01:37:42 +07:00
#if canImport(SwiftUI) && DEBUG
2021-04-23 14:19:47 +07:00
import SwiftUI
2021-05-05 01:37:42 +07:00
struct SwiftLeeViewRepresentable: UIViewRepresentable {
func makeUIView(context: Context) -> UIView {
return UIStoryboard(name: "Main", bundle: Bundle.main).instantiateInitialViewController()!.view
2021-04-23 14:19:47 +07:00
}
2021-05-05 01:37:42 +07:00
func updateUIView(_ view: UIView, context: Context) {
2021-04-23 14:19:47 +07:00
}
}
2021-05-05 01:37:42 +07:00
@available(iOS 13.0, *)
struct SwiftLeeViewController_Preview: PreviewProvider {
2021-04-23 14:19:47 +07:00
static var previews: some View {
2021-05-05 01:37:42 +07:00
SwiftLeeViewRepresentable()
2021-04-23 14:19:47 +07:00
}
}
2021-05-05 01:37:42 +07:00
#endif
2021-04-23 14:19:47 +07:00
```
2021-04-23 14:25:02 +07:00
Enable canvas option like this
<img src="https://github.com/jphong1111/Useful_Swift/blob/main/Images/preview%20using%20canvas.png">
2021-04-23 14:34:10 +07:00
**You are GOOD TO GO** 👏👏👏
2021-04-23 14:38:50 +07:00
2021-04-23 14:39:56 +07:00
<img src="https://github.com/jphong1111/Useful_Swift/blob/main/Images/preivew_screenShot.png">
2021-04-24 00:01:19 +07:00
## Write README.md
2021-04-24 00:01:53 +07:00
[This](https://medium.com/@saumya.ranjan/how-to-write-a-readme-md-file-markdown-file-20cb7cbcd6f) will help you to write a README.md file more dynamically 👍
2021-05-01 09:22:58 +07:00
2021-05-21 10:55:16 +07:00
## Roadmap for iOS Developer
check this out [here](https://github.com/BohdanOrlov/iOS-Developer-Roadmap)
2021-05-01 09:22:58 +07:00
## Author
2021-05-01 09:23:20 +07:00
This README.md file is written by **Jungpyo Hong (Dennis)**
2021-05-24 09:11:33 +07:00
email: ghdwjdvy96@gmail.com