# Useful Swift Things

## Content - [Coding Convention](#Coding-convention) - [Swift Lint](#Swift-lint) - [Design Pattern](#Design-Pattern) - [Delegation](#Delegation) - [Singleton](#Singleton) - [Observer](#Observer) - [Code Structuring](#Code-Structuring) - [MVC](#MVC) - [MVVM](#MVVM) - [VIPER](#VIPER) - [UIDesign](#UIDesign) - [Helper](#Helper) - [Email, Message, Call](#email-message-call) - [Network Layer](#Network-Layer) - [Image Picker](#Image-Picker) - [File Manager](#File-Manager) - [Video Downloader](#Video-Downloader) - [Image Downloader](#Image-Downloader) - [Location Manager](#Location-Manager) - [API](#API) - [JSON](#JSON) - [UserDefaults](#UserDefaults) - [How to find documentDirectory](#How-to-find-documentDirectory) - [Core Data](#Core-Data) - [Third Party Library](#Third-Party-Library) - [GCD](#GCD) - [DispatchQueue](#DispatchQueue) - [DispatchGroup](#DispatchGroup) - [DispatchWorkItem](#DispatchWorkItem) - [Thread Sanitizer](#Thread-Sanitizer) - [Testing](#Testing) - [Code Coverage](#Code-Coverage) - [Unit Test](#Unit-Test) - [UI Test](#UI-Test) - [IAP](#IAP) - [APNS](#APNS) - [FRP](#FRP) - [Error Search](#Error-Search) - [Useful Stuff](#Useful-Stuff) - [Show Preview in UIKit(Build UI with Code Base)](#show-preview-in-uikitbuild-ui-with-code-base-----) - [Write README.md](#write-readmemd) - [Roadmap for iOS Developer](#Roadmap-for-iOS-Developer) ## Coding convention set of guidelines for a specific programming language that recommend programming style ### Swift Style Guide - [Swift Style Guide](https://github.com/linkedin/swift-style-guide) ### Swift Lint The way of force you to adapt coding convention >otherwise project build will **FAILED** - [Swift Lint](https://github.com/realm/SwiftLint) apply for all project:+1: ```swift if which swiftlint >/dev/null; then swiftlint else echo "error: SwiftLint not installed, download from https://github.com/realm/SwiftLint" exit 1 fi ``` put .yml file into root folder and apply following code in Build Phases **You can modify(delete) SwiftLint Option with opening .yml file** > Shift + Command + . will show the hidden file ## Design Pattern Design pattern is Check [this](https://refactoring.guru/design-patterns/swift) website for design pattern in Swift ### Delegation ```swift weak var delegate: SomeProtocol? ``` ### Singleton ```swift class SingletonPattern { static let manager = SingletonPattern() private init() {} } ``` ### Observer 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. ## Code Structuring ### MVC ### MVVM ##### MVC vs MVVM M -> Model – Which holds the application data V –> View – It displays the data that is stored in model. These are visual elements through which a user interacts. These are subclasses of UIView VM –> View Model – Transform model information/data and it interacts with controller or view to display those informations. C –> Controller class – It will be there but the responsibility of view business logic has been removed and give to view model ### VIPER ## UIDesign ### HIG(Human Interface Guidelines) - [Apple UI Kit](https://developer.apple.com/documentation/uikit) - [iOS Design Guide](https://ivomynttinen.com/blog/ios-design-guidelines) ### iOS icon - [icon8](https://icons8.com/) You can download icons imge for your **APP** - [appicon](https://appicon.co/) generate the app icon size ### UIdesign inspiration - [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 All files are resuable files and protocol oriented. **Just Copy and Paste inside your project and use it!!** 👍 ## Email, Message, Call You can check the file in the follow link - [Email, Message, Call](https://github.com/jphong1111/Useful_Swift/blob/main/Helper/ConversationManager.swift) ### Usage import MesaageUI first ```swift import MessageUI ``` Then use it > Don't forget to extend the mail, message delegate to your ViewController! ```swift lazy var conversation = ConversationManager(presentingController: self, mailDelegate: self, messageDelegate: self, viewController: self) @IBAction private func sendEmail(_ sender: UIButton) { conversation.sendEmail(feedback: MailFeedback(recipients: ["abcd@google.com"], subject: "FeedBack", body: "Write feedback here")) } @IBAction private func sendMessage(_ sender: UIButton) { conversation.sendMessage(feedback: MessageFeedBack(recipients: ["1111111111"], body: "Type here")) } @IBAction private func startCall(_ sender: UIButton) { conversation.makeCall(number: "1111111111") } ``` Good To GO 👏👏👏 > See Example [here](https://github.com/jphong1111/ImageMessageHandler_DemoApp) ## Network Layer - [Network Layer](https://github.com/jphong1111/Useful_Swift/tree/main/Helper/Network%20Layer) ### Usage First, set the base URL in **EndPointType file** > Don't forget to put your API key in it! ```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() ``` for **YourAPI part**, simply create a new **enum** with cases about specific api URL > 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" case .third(let name): return "\(name).json" } } } ``` then, use it like this ```swift router.request(.first(country: London)) { [weak self] (results: Result) 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** 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) This reusable network layer files for referenced from [here](https://medium.com/flawless-app-stories/writing-network-layer-in-swift-protocol-oriented-approach-4fa40ef1f908) > Also [Alamofire](https://github.com/Alamofire/Alamofire) will be a great option for Network Layer! ## Image Picker - [Image Picker](https://github.com/jphong1111/Useful_Swift/blob/main/Helper/ImagePickerHandler/ImagePicker.swift) ### Usage 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) ## File Manager - [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! Good To GO 👏👏👏 ## Video Downloader - [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 👏👏👏 ## 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) } ``` Just **change urls into your image URL** > UIImageWriteToSavedPhotosAlbum will take care it to download to device. > For more info go [here](https://www.hackingwithswift.com/example-code/media/uiimagewritetosavedphotosalbum-how-to-write-to-the-ios-photo-album) Good To GO 👏👏👏 ## Location Manager - [Location Manager](https://github.com/jphong1111/Useful_Swift/tree/main/Helper/LocationHandler/LocationManager.swift) ## API 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. ## JSON JSON is a language-independent data format > Which is relative with **KEY - VALUE** pair ```json { "main": [ { "title": "example1", "body": "body1" }, { "title": "example2", "body: "body2" } ] } ``` ### JSON parser extension for Chrome This extension makes JSON more structable [JSON parser pro](https://chrome.google.com/webstore/detail/json-viewer-pro/eifflpmocdbdmepbjaopkkhbfmdgijcc) **FREE** :+1: ### JSON Decoding 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 } ``` 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!! ### JSONSerialization ## UserDefaults 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 > UserDefaults has to have **key-value** pair ### 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 - If store data is small ### 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 } ``` 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 ### Usage 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)" } } ``` You can your plist file like this! Declare Userdefault like this! ```swift let defaults = UserDefaults.standard ``` > **standard** allows to access from anywhere inside device **With using set function, you can set userdefaults** **Also these function will allow to get a data from plist** **You are GOOD TO GO** 👏👏👏 ## Core Data > Image From London App Brewery ### Various API Site - [rapidAPI](https://www.rapidapi.com) ## Third Party Library [This github](https://github.com/vsouza/awesome-ios) contains all the popular libraries in Swift:+1: Recommand Useful Library - [SDWebImage] - Download and set image Library - [Hero] - Various kind of animation with using Segue - [Alamofire] - Network Layer tool - [RxSwift] - Reactive Programming in Swift ## GCD GCD(Grand Central Dispatch) is a low-level API for managing concurrent operations. It can help you improve your app’s responsiveness by deferring computationally expensive tasks to the background. ### DispatchQueue An object that manages the execution of tasks serially or concurrently on your app's main thread or on a background thread. #### main We can say main is a serial queue #### global() We can say global is a concurrent queue ### DispatchGroup ### DispatchWorkItem ### 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. #### How to Use Address Sanitizer Go to this Option and Click **EDIT SCHEME...** 👈 And then go to **RUN** and check **THREAD SANITIZER** 👈 ## Testing Before start your Testing, add coverage will be a good option to show the result of test ### Code Coverage First, check code coverage Then, go to **EDIT SHEME**, check like this ### Unit Test ### UI Test ## IAP IAP stands for **In App Purchase** ## APNS APNS stands for **Apple Push Notification service** ## FRP Functional Reactive Programming a.k.a [RxSwift](https://github.com/ReactiveX/RxSwift) ## Error Search Find your common error here [Error Search](https://github.com/jphong1111/Useful_Swift/blob/error-search/README.md) ## Useful Stuff ### Show Preview in UIKit(Build UI with Code Base) 👍 👍 👍 👍 👍 Copy this code and Paste into your controller ```swift #if canImport(SwiftUI) && DEBUG import SwiftUI struct SwiftLeeViewRepresentable: UIViewRepresentable { func makeUIView(context: Context) -> UIView { return UIStoryboard(name: "Main", bundle: Bundle.main).instantiateInitialViewController()!.view } func updateUIView(_ view: UIView, context: Context) { } } @available(iOS 13.0, *) struct SwiftLeeViewController_Preview: PreviewProvider { static var previews: some View { SwiftLeeViewRepresentable() } } #endif ``` Enable canvas option like this **You are GOOD TO GO** 👏👏👏 ## Write README.md [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 👍 ## Roadmap for iOS Developer check this out [here](https://github.com/BohdanOrlov/iOS-Developer-Roadmap) ## Author This README.md file is written by **Jungpyo Hong (Dennis)**