# Coding Standard guidelines 🏗
##### 🚧🚧👷♂️This is "Work in progress" so please feel free to comment or suggest change.👷♂️🚧🚧
I am writing this guide in "if this, then that" fashion. I would have an example from code that has warning then I will show one of the correct ways to handle it.
**1. Variable `nil` check**
if (followupStartDate != nil) {
timePicker.setDate(followupStartDate!, animated: false)
}
Then
if let followupStartDate = followupStartDate {
timePicker.setDate(followupStartDate, animated: false)
}
**2. No `break` is needed in `case`**
only `default` is an exception.
``` swift
case 0:
days = 0
break
```
then
``` swift
case 0:
days = 0
```
**3. Any `delegate` and `datasource` methods need to broken into `extension`**
``` swift
func numberOfComponents(in pickerView: UIPickerView) -> Int { }
```
then
```swift
extension EditLogViewController: UIPickerViewDelegate, UIPickerViewDataSource {
func numberOfComponents(in pickerView: UIPickerView) -> Int { }
```
**4. Any code section needs to be marked by `// MARK: Whatever the section represents`**
**5. Explicit unwrapping (`!`) is tricky. so we would handle case by case.**
* *When getting the viewcontroller or storyboard*
```swift
func openCommentEditView() {
fieldTitle.text = ""
let activityCommentsViewController =
SBManager.instance.activityStoryboard.instantiateViewController(withIdentifier: "ActivityCommentsViewController")
➡️ as! ActivityViewController
ActivityViewController.activity = callLog
ActivityViewController.delegate = self
navigationController!.pushViewController(ActivityViewController, animated: true)
}
```
then
```swift
func openCommentEditView() {
fieldTitle.text = ""
guard let ActivityViewController = StoryboardManager.instance.activityStoryboard.instantiateViewController(withIdentifier: "ActivityViewController") as? ActivityViewController
else {
showErrorBanner(title: AppError.Generic.Error.title, subtitle: AppError.Generic.Error.unableToCreateView, actionHandler: nil)
return
}
ActivityViewController.activity = callLog
ActivityViewController.delegate = self
navigationController?.pushViewController(ActivityViewController, animated: true)
}
```
* **When property of object is optional**
To avoid explicit unwrap by providing default value.
```swift
processMins = comp.hour! * 60 + comp.minute!
```
then
```
processMins = (comp.hour ?? 0) * 60 + (comp.minute ?? 0)
```
* **Any ViewController have optional property** `navigationController`
```swift
navigationController!.navigationBar.tintColor = UIColor.mainTealColor()
```
then
```swift
navigationController?.navigationBar.tintColor = UIColor.mainTealColor()
```
It can safely access by optional operator(`?`)
* **If internal variable is Optional**
*var startDate: Date?* // for example
```swift
if (startDate == nil) {
cell.content.textColor = UIColor.lightGray
cell.content.text = "Select"
}
else {
cell.content.textColor = UIColor.black
cell.content.text = activityShowFormatter.string(from: startDate!)
}
```
then
```swift
if let startDate = startDate {
cell.content.textColor = UIColor.black
cell.content.text = activityShowFormatter.string(from: startDate)
} else {
cell.content.textColor = UIColor.lightGray
cell.content.text = "Select"
}
```
**6. Using [unowned self] or [weak self] in closures (Fixes memory issues)**
```swift
someFunction(val) { (auth, error) in
self.ShowError(error)
}
```
then
```swift
someFunction(val) { [unowned self](auth, error) in
self.ShowError(error)
}
```
or
```swift
someFunction(val) { [weak self](auth, error) in
self?.ShowError(error)
}
```
**7. How to handle double closure warning `(multiple_closures_with_trailing_closure)`**
`
Warning is due to as we are using traling clousure when we have two closure `success` and `failure`
We need to avoid use double trailing clousure
```
GoogleAPIHelper.getLocationFromAddress( {...}) {...}
```
then
we just need to drop closure techniue. so solution would be
```
GoogleAPIHelper.getLocationFromAddress(success: {...}, failure: {...})
```
**8. `where` in the `for` loop**
*For Where Violation: `where` clauses are preferred over a single `if` inside a `for`. (for_where)*
```swift
for companyAddress in companyAddresses {
if (companyAddress.defaultInd == true) {
defaultAddressId = companyAddress.addressId
break
}
}
```
then
```swift
for companyAddress in companyAddresses where companyAddress.defaultInd == true {
defaultAddressId = companyAddress.addressId
break
}
```
**🚨9. Implement DRY rule when come to coredata save code snippet**
To make error handling better, consistent and remove code duplication. We need to use following extension.
🚨🚨🚨🚨🚨 Please test your code throughly for saving. 🚨🚨🚨🚨🚨
```swift
extension UIViewController {
var appDelegateHandle: AppDelegate? {
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
return appDelegate
}
return nil
}
func managedObjectContextToCoreData() {
do {
try appDelegateHandle?.getManagedObjectContext()?.save()
}
catch {
BannerNotification().forError(title: AppError.Generic.Error.title,
subtitle: AppError.Generic.Error.unableToSaveData,
actionHandler: nil)
}
}
}
```
**10. Dead code removal**
If you see comment code in codebase. just remove it. Dead code is not helpful in any regard. Mostly it is the code that we thought to remove but forgot to clean up.
**11. Delegate must be `weak` (weak_delegate)**
Delegates must be weak to avoid the retain cycles and avoid any memory related issues.
```swift
var delegate: CardDetailViewControllerDelegate?
```
then
```swift
weak var delegate: CardDetailViewControllerDelegate?
```
**12. UIViewController's `optional` property navigationController**
There is no need to explicitly unwrap it `optional chaining` is safer way(as shown below).
```swift
self.navigationController!.pushViewController(editCardViewController, animated: true)
```
then
```swift
self.navigationController?.pushViewController(editCardViewController, animated: true)
```
**13. Deleting empty handler in `UIAlertAction`**
`UIAlertAction(title: "", style: .cancel, handler: nil)`
Handler is `optional`. It can can be either set to nil or can be omit all together.
```swift
let cancelAction = UIAlertAction(title: LOCALSTR("Cancel"), style: .cancel) { action -> Void in }
```
then
```swift
let cancelAction = UIAlertAction(title: "", style: .cancel, handler: nil)
```
or
```swift
let cancelAction = UIAlertAction(title: "", style: .cancel)
```
**14. Make use of `if let` to nil check and `conditional check`
Old code**
```swift
if (officeAddress!.address2 != nil && officeAddress!.address2 != "") {
contactAddress["Address2"] = officeAddress!.address2
}
```
then
```swift
if let address2 = officeAddress.address2, address2.isEmpty == false {
contactAddress["Address2"] = address2
}
```
**15. `Variable` and `constant` declaration at the top of the `current` scope**
❌ Unpreffered way
```swift
func getPersistentStoreCoordinator() -> NSPersistentStoreCoordinator? {
if let persistentStoreCoordinator = persistentStoreCoordinator {
return persistentStoreCoordinator
}
❌let storeURL = applicationDocumentsDirectory()?.appendingPathComponent("cosential-db3.sqlite")
guard let getMOModel = getManagedObjectModel()
```
✅ Preffered way
```swift
func getPersistentStoreCoordinator() -> NSPersistentStoreCoordinator? {
✅let storeURL = applicationDocumentsDirectory()?.appendingPathComponent("cosential-db3.sqlite")
if let persistentStoreCoordinator = persistentStoreCoordinator {
return persistentStoreCoordinator
}
guard let getMOModel = getManagedObjectModel()
```
**16. When property is `read-only`. There is no need of explicit getter.**
❌
```swift
class var usedDiskSpace:String {
get {
return ByteCountFormatter.string(fromByteCount: usedDiskSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.file)
}
}
```
then
✅
```swift
class var usedDiskSpace:String {
return ByteCountFormatter.string(fromByteCount: usedDiskSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.file)
}
```
**🚨17. Combining multiple condition together**.
As you can see inner most code is only executing when all condition are met. Rather than checking them separatly, it can be done with if let and chaining conditions together.
❌
```swift
if (filterSet.companyTypes != nil) {
let typeIds = (try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(filterSet.companyTypes!)) as? [Int] ?? []
if (typeIds.count > 0) {
//// Inner most code
}
```
then
✅
```swift
if let filterSetCompanyType = filterSet.companyTypes,
let typeIds = (try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(filterSetCompanyType)) as? [Int],
typeIds.count > 0 {
//// Inner most code
}
```
**18. explicit unwrap isn't needed when using nil coalescing operator`??`**
```swift
❌ let page = self.page(self.notesView!.text ?? "")
```
then
```swift
✅ let page = self.page(self.notesView?.text ?? "")
```
**19. No explicit unwrap `!` is needed on LHS**
If it has a value it would get assigned unwrap has no effect.
❌
```swift
contact!.birthday = contactData["Birthday"] as? String ?? ""
```
then
✅
```swift
contact?.birthday = contactData["Birthday"] as? String ?? ""
```
**20. Replacing Magic numbers with `let` in top of scope with comment**.
❌
```swift
return Int(Character(sectionTitle).unicodeScalars.first!.value - 65)
```
then
✅
```swift
// top of scope
let someMagic = 65
//// some code
//// some code
return Int(Character(sectionTitle).unicodeScalars.first!.value - someMagic)
```