Skip to content

sahandnayebaziz/Useful_Swift

Β 
Β 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Useful Swift Things

Feel free to fork this repository and pull requests!

Content

Coding convention

set of guidelines for a specific programming language that recommend programming style

Swift Style Guide

Swift Lint

The way of force you to adapt coding convention

otherwise project build will FAILED

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 website for design pattern in Swift

Delegation

weak var delegate: SomeProtocol?

Singleton

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(Architecture)

MVC

MVC pattern stands for Model - View - Controller

  • 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.

MVVM

MVVM patterns stand for Model - View - ViewModel

MVC vs MVVM

  • Model – Which holds the application data

  • View – It displays the data that is stored in model. These are visual elements through which a user interacts. These are subclasses of UIView

  • View Model – Transform model information/data and it interacts with controller or view to display those informations.

  • Controller class – It will be there but the responsibility of view business logic has been removed and give to view model

You can check App example of using MVVM here

VIPER

  • 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.

For more info, go here

UIDesign

HIG(Human Interface Guidelines)

iOS icon

  • SF Symbols Download SF Symbols2 for more icons!
  • icon8 You can download icons imge for your APP
  • appicon generate the app icon size

UIdesign inspiration

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

Usage

import MessageUI first

import MessageUI

Then use it

Don't forget to extend the mail, message delegate to your ViewController!

    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

Network Layer

Usage

First, set the base URL in EndPointType file

Don't forget to put your API key in it!

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

private let router = Router<YourAPI>()

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!

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

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

If you want to see how can I use Network Layer in Project, check this

This reusable network layer files for referenced from here

Also Alamofire will be a great option for Network Layer!

Image Picker

Usage

Copy and Paste in your project and then declare Image Picker object inside your project

lazy var imagePicker = ImagePicker(presentationController: self, delegate: self)

Then, extend ImagePickerDelegate to your viewController

extension ViewController: ImagePickerDelegate {
    func didSelect(image: UIImage?) {
        self.yourImageView.image = image
        self.dismiss(animated: true, completion: nil)
    }
}

Good To GO πŸ‘πŸ‘πŸ‘

See Example here

File Manager

Usage

Copy and Paste in your project

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

Usage

Make an object of VideoManager inside your code

let videoManager = VideoManager()

use downloadVideoLinkAndCreateAsset function to start download with entering URL

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

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

Good To GO πŸ‘πŸ‘πŸ‘

Location Manager

Currently Working

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

{
    "main": [
        {
            "title": "example1",
            "body": "body1"
        },
        {
            "title": "example2",
            "body: "body2"
        }
    ]
}

JSON parser extension for Chrome

This extension makes JSON more structable JSON parser pro FREE πŸ‘

JSON Decoding

To use JSON Decoding in swift, you have to define the model to be Codable or Decodable

public typealias Codable = Decodable & Encodable

Decodable can only decode the json data. Can't encoded json file!!

struct User: Codable {
    var first_name: String
    var last_name: String
    var country: String
}

To use JSONDecoding, declare JSONDecoder and use decode() function

 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

JSONSerialization is a old way of decode the JSON file

Various API Site

UserDefaults

The UserDefaults class provides a programmatic interface for interacting with the defaults system. Check Apple Document 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

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.

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!

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

Use Core Data to save your application’s permanent data for offline use, to cache temporary data, and to add undo functionality to your app on a single device.

Core Data in Swift is using SQLite as DEFAULT

Image From London App Brewery

Set Up Core Data

Simply Click Core Data check box when you create a new project

If you want to attach Core Data in exsiting project

Create Data Model file first

Then import CoreData inside your AppDelegate.swift file

import CoreData

And Copy and Paste this lines of code inside your AppDelegate.swift file

    // 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

let container = NSPersistentContainer(name: "Your DataModel file name")

And goto SceneDelegate.swift file, copy below lines of code and replace yours

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()
    }

If your target is below iOS13, put this line of code in side your applicationWillTerminate of AppDelegate.swift file

self.saveContext()

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

Once you create your own Entities & Attributes, go to Inspector and change Module to CurrentProductModule

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.

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)

CoreDataClass, CoreDataProperties are located in below

/Users/dennis/Library/Developer/Xcode/DerivedData/CoreDataUserDefaultPractice-hisefjfyuvglrjekndpftwazftug/Build/Intermediates.noindex/CoreDataUserDefaultPractice.build/Debug-iphonesimulator/CoreDataUserDefaultPractice.build/DerivedSources/CoreDataGenerated/CoreDataUserDefaultPractice

And CoreDataClass, CoreDataProperties are looking like this,

If your code can run it but didn't get your Entities, Rebuild it or Restart your Xcode

Store Data

Declare context as a global variable

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

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

print(FileManager.default.urls(for: .documentDirectory, in: .userDomainMask))

You can check Entities, Properties inside that file

Load Data

Refer this code and apply it to your code wherever you want to reload it

    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

Update Data

Simply use setValue function so that you can update your value in DB

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

context.delete(itemArray[0])

change number for dynamic!

You are GOOD TO GO πŸ‘πŸ‘πŸ‘

Third Party Library

This github 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 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

In App Purchase(IAP)

IAP stands for In App Purchase

APNS

APNS stands for Apple Push Notification service

FRP

Functional Reactive Programming a.k.a RxSwift

Error Search

Find your common error here

Error Search

Useful Stuff

Show Preview in UIKit(Build UI with Code Base) πŸ‘ πŸ‘ πŸ‘ πŸ‘ πŸ‘

Copy this code and Paste into your controller

#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 will help you to write a README.md file more dynamically πŸ‘

Roadmap for iOS Developer

check this out here

Author

This README.md file is written by Jungpyo Hong (Dennis) email: ghdwjdvy96@gmail.com

About

List of useful iOS & Swift stuff!!

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Swift 100.0%