Showing posts with label ios. Show all posts
Showing posts with label ios. Show all posts

Thursday, May 24, 2018

Typical iOS practical test - interview

In this tutorial we will learn how to make an App quickly in practical interview test and stand out of crowd by doing some extra good code. Here is a list of things you could learn from this code base.

  • use of closures
  • lazy loading of images using OperationQueue
  • lazy variable use
  • unit test case writing
  • protocol use in swift
  • DispatchQueue  async use
  • class extension
  • Custom UITableViewCell
  • operationQueue handling
  • use of generics
  • subclass use of Operation
  • decodable and decoder use- Easy way to parse JSON
  • use of Url session
  • overriding of methods and variables
  • enum creation and use.


Here is the final output of this tutorial.



Lets start coding.
Here is a link which we are going to parse. It has list of top free apps from the iTunes app store. So here you can see the data which we need is in array called "Results" and that is under dictonary with key "Feed". we are going to parse and build the array of result array.



So we have a view-controller with Tableview and custom cell to show the image and text details of the app. we take UINavigationController and set our viewcontroller as root viewcontroller. In viewcontroller we have tableview and custom cell which has two labels, UIImageView and one activity indicator.


Now we need one ViewModel as middle to communicate with our model and update ourUI. ViewModel is requesting for the data to model and will be holding the result along with model object. Here you see ViewModel is actually cleaver than view-controller and our vc is dumb, but filled with all the equipments it requires. here you see viewmodel is actual  mind of our viewcontroller and control every aspect of data.


Now its time to create a model it actually holds the actual business logic and understanding what and how to call the web service, using which class too. after that it parse the result using jsonparse class which is leveraging two new swift features. one is generics and other is decodable.





Now to create request we have one class as RederRequest and it has actual url path where we need to connect at this point of time we do not require to send any data, if we need that that we can add that in the same class under url content function.


Decodable is useful to convert the response to data-class. Here AppList is a data class or entity and there is no need to map using 'valueForKey:'


We get the response and in response we have url of app image instead of actual image so we will implement lazy loading using operation to download the image. First we will ask for the images which are currently visible on the UI. And as user moves to new list we will ask for that images.
Here is a code of image downloader to download the image asynchronous. We will call this code from model to download.


This is the implementation of ImageDownloader class it download images and save as data in the AppInfo object and update the status of image.



Now Lets move to XCTest cases.
Here we will write some test cases. There are two functions written to cover the code and once we run it we can see how much code is actually covers.


Check the code coverage image where you can see some number highlighted in right side it shows how many times this code ran last time. 'appdescription' function has been called 19 time last time the code executed.


This is the find consolidated coverage of our app it is actually around 74%. An app should have at least 80% of coverage to cover all major scenarios. we are short to 6%.

Download full code from Github https://github.com/it-sam/iOS-practical

Friday, July 14, 2017

Swift access modifiers

Swift access modifiers

Swift access modifiers

Open:
open classes and class members can be subclassed and overridden both within and outside the defining module (target). Open access is the highest (least restrictive) access level.

Public:
public classes and class members can only be subclassed and overridden within the defining module (target).

Internal:
Enables an entity to be used within the defining module (target). You typically use internal access when defining an app’s or a framework’s internal structure.

FilePrivate:
Restricts the use of an entity to its defining source file. You typically use fileprivate access to hide the implementation details of a specific piece of functionality when those details are used within an entire file.

Private:
Restricts the use of an entity to its enclosing declaration. You typically use private access to hide the implementation details of a specific piece of functionality when those details are used only within a single declaration. private access is the lowest (most restrictive) access level.

Final:
The final keyword is not an access level but you can add it to any of the access levels (apart from open) to prevent subclassing or overriding.


Now the question is What does it mean by same module?
Let’s understand it by example: many times we subclass UITextField (class), which is a part of UIKIT (Different module) but we can do this because it is defined as open. Same applies for class member and methods.

@available(iOS 2.0, *)
open class UITextField : UIControl, UITextInput, NSCoding, UIContentSizeCategoryAdjusting {
...
...
}

UITextField: Swift access modifiers

Some other observations: (I have checked it with swift 3.0.)

In order to apply the open and public access modifiers we need to inherit our class from NSObject. Or we may get below error while using outside of class.
'openClass' initializer is inaccessible due to 'internal' protection level.
'publicClass' initializer is inaccessible due to 'internal' protection level.
'fileprivateFunc' is inaccessible due to 'fileprivate' protection level

We cannot inherit public class outside the module. We get below error:
Cannot inherit from non-open class 'publicClass' outside of its defining module

We cannot access internal method or object outside the module.
'internalObject' is inaccessible due to 'internal' protection level

In other file or module,We get below error when we try to create object of FilePrivate class and private class respectively.
Use of undeclared type 'fileprivateClass'
Use of undeclared type 'privateClass'

In same file, we can inherit or create object of private class as below and we can access all class members and methods which are not private.

fileprivate var privateClassObject = privateClass()

private class IprivateClass :privateClass {
}

Here is a link of apple document for more details.

Thursday, July 13, 2017

VIPER- Class binding using Protocol

In last post we have seen how to bind all classes together. In this post we would see app flows from view controller to interactor and to view controller.To make it more decoupled we would generate some protocols and implement it in classes.

Step:1 list-ViewController
Architecting iOS Apps with VIPER - App event flow in VIPER
override func viewDidLoad() {
        super.viewDidLoad()
        DispatchQueue.global().async {
            self.eventHandler?.updateView()
        }
    }

Step:2 list-Presenter
Architecting iOS Apps with VIPER - App event flow in VIPER

func updateView() {
        listInteractor?.findListData()
    }

Step:3 list-Interactor
Architecting iOS Apps with VIPER - App event flow in VIPER


func findListData() {
        //Find data
        //output?.foundListData(aList: nil);
        let reader = FileReader()
        if let data = reader.readJsonFile(name: "company") {
            let myArr:NSArray? = ParseData(aObject: data)
            if myArr != nil {
                output?.foundList(aList: myArr);
            }
        }
    }

Step:4 list-Presenter
Architecting iOS Apps with VIPER - App event flow in VIPER

func foundList(aList:NSArray?) {
        let sortedArray:NSArray? = self.SortCompanyList(aList: aList)
        if(sortedArray != nil) {
            userInterface?.reloadList(alist: sortedArray)
        }
        else {
            userInterface?.showNoContenctView()
        }
    }

Protocols:
1) ViewController Interface:
Implemented   by ViewController
Object owned by Presenter
Architecting iOS Apps with VIPER - Protocol binding in VIPER

protocol listViewInterface {
    func showNoContenctView()
    func reloadList(alist:NSArray?)
}
*********************************************************
class ViewController: UIViewController,listViewInterface
 {
  //MARK: listViewInterface methods implementation
    func reloadList(alist:NSArray?) {
        //reload table view
    }
    func showNoContenctView() {
     //Show alert code
    }
 }
*********************************************************
class listPresenter: NSObject {
    var userInterface:listViewInterface?
}

2) Presenter Interface:
Implemented by Presenter
Object owned by ViewController
Architecting iOS Apps with VIPER - Protocol binding in VIPER

protocol listPresenterInterface {
    func updateView();
}
*********************************************************
class listPresenter: NSObject,listPresenterInterface {
    var userInterface:listViewInterface?
    func updateView() {
        //Call for data adjustment and interactor calling
    }
}
*********************************************************
class ViewController: UIViewController,listViewInterface {
   var eventHandler:listPresenterInterface?
   override func viewDidLoad() {
     super.viewDidLoad()
     self.eventHandler?.updateView();
   }

   //MARK: listViewInterface implementation
    func reloadList(alist:NSArray?) {
        //reload table view
    }
    func showNoContenctView(){
        //Show alert code
        }
 }


3) Interactor Input Interface:
Implemented   by interactor
Object owned  by presenter
Architecting iOS Apps with VIPER - Protocol binding in VIPER

protocol listInteractorInput {
    func findListData()
}
*********************************************************
class listInteractor: NSObject,listInteractorInput {
    func findListData() {
        //Find data
    }
*********************************************************
class listPresenter: NSObject,listPresenterInterface {
    var listInteractor:listInteractorInput?
    func updateView() {
     //Code for data adjustment and interactor calling
     listInteractor?.findListData();
    }
}

4) Interactor output Interface:
Implemented   by presenter
Object owned  by interactor
Architecting iOS Apps with VIPER - Protocol binding in VIPER

protocol listInteractorOutput {
    func foundList(aList:NSArray?)
}
*********************************************************
class listPresenter: NSObject,listPresenterInterface,listInteractorOutput {
    var listInteractor:listInteractorInput?
    var userInterface:listViewInterface?
    
    func updateView() {
        listInteractor?.findListData();
    }
    func foundList(aList:NSArray?) {
       userInterface?.reloadList(alist: sortedArray);
    }
}
*********************************************************
class listInteractor: NSObject,listInteractorInput {
    var output:listInteractorOutput?
    func findListData() {
        //Find data
    }
}

Note:Presenter is implementing two protocols.
This is the end of the post. In next post we will see how VIPER is useful for testing and coverage.

Thursday, July 6, 2017

VIPER: Router and wireframe - Class binding

We will see binding of all classes.Let us bind for list view.

Here is a list of classes with whom we are going to interact.
AppDelegate – Standard UIApplicationMain default class.
AppDependencies – A class which has methods to bind all classes.
Root-wireframe - A class which has all possible kind of transition code. (like push, pop, present etc.) List-wireframe - A class knows how to show its UI and all possible forward flow.

And other all classes that we have seen previous are presenter, interactor, view controller and entity. Here is a step by step process to bind all the classes.

Step:1 class name: AppDelegate We create object of dependency class.
Architecting iOS Apps with VIPER

let appDependencies = AppDependencies()

Step:2 class name: AppDelegate, With dependency class we call its method.
Architecting iOS Apps with VIPER


func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        let wireframe = appDependencies.configureDependencies()
        return true
    }

Step:3 class name: AppDependencies  In dependency class we can put all shared instance object and other objects we put it in a method.
Architecting iOS Apps with VIPER

class AppDependencies {
    let rootWireFrame = RootWireframe()
    //this is the root object so we need to create here, others go to their own function
    //return value could be replaced with wireframe object

    func configureDependencies() -> listWireFrame {
        let listWireframe = listWireFrame()

        listWireframe.rootWireframe = rootWireFrame
        return listWireframe
    }
}

Step:4 class name: AppDependencies
Architecting iOS Apps with VIPER

func configureDependencies() -> listWireFrame {
        let listWireframe = listWireFrame()
 let Presenter = listPresenter()

 listWireframe.rootWireframe = rootWireFrame
 listWireframe.listPresenter = Presenter
 return listWireframe
}

Step:5 class name: AppDependencies
Architecting iOS Apps with VIPER

func configureDependencies() -> listWireFrame {
        let listWireframe = listWireFrame()
        let Presenter = listPresenter()
        let Interactor = listInteractor()
        
        listWireframe.listPresenter = Presenter
        Presenter.listInteractor = Interactor
        return listWireframe
    }

Step:6 AppDependencies
Architecting iOS Apps with VIPER

func configureDependencies() -> listWireFrame {
        let listWireframe = listWireFrame()
        let Presenter = listPresenter()
        let Interactor = listInteractor()
        
        listWireframe.listPresenter = Presenter
        Presenter.listInteractor = Interactor
        Interactor.output = Presenter
        listWireframe.rootWireframe = rootWireFrame
        return listWireframe
    }

Step:7 class name: AppDelegate
Architecting iOS Apps with VIPER

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        let wireframe = appDependencies.configureDependencies()
        wireframe.presentListInterfaceFromWindow(window: window!)
        return true
    }

class name: list-wireframe
func presentListInterfaceFromWindow(window: UIWindow) {
        let viewController = listViewControllerFromStoryboard()
        viewController.eventHandler = listPresenter
        listVC = viewController
        listPresenter!.userInterface = viewController
        rootWireframe?.showRootViewController(viewController: viewController, inWindow: window)
    }

Step:8 class name: list-wireframe
Architecting iOS Apps with VIPER

func presentListInterfaceFromWindow(window: UIWindow) {
        let viewController = listViewControllerFromStoryboard()
        viewController.eventHandler = listPresenter
        listVC = viewController
        listPresenter!.userInterface = viewController
        rootWireframe?.showRootViewController(viewController: viewController, inWindow: window)
    }

Here is a full flow of binding of all classes.
Architecting iOS Apps with VIPER



Sunday, June 25, 2017

VIPER: Interactor and Entity

In this post, we will see interactor work and entity engagement with it. Currently we have not attached it with any kind of data, now we will load up some to data and try to show it in view which is all the way back to presenter.

Use Case: Now we know about view and presenter, it’s time for Interactor. We want to see name of the person and the company in UIView. For that we have one JSON file which we will load. 

Task: Implement interactor, implement file reader, read the file, convert data in to model, transform it as per view and show the details.
Anticipated output:
VIPER: Interactor and Entity

Here is a JSON file as of now which we want to load and show the data.
//JSON file
[{
  "_id": "58f9a19680685a4e1e6d5016",
  "index": 0,
  "guid": "0b10fe86-a222-4ca5-a094-0082b7d4c1af",
  "isActive": false,
  "balance": "$2,107.15",
  "picture": "http://placehold.it/32x32",
  "age": 35,
  "eyeColor": "green",
  "name": {
   "first": "Bertha",
   "last": "Irwin"
  },
  "company": "COMSTAR",
  "email": "bertha.irwin@comstar.net",
  "phone": "+1 (806) 584-3949",
  "address": "303 Vermont Street, Concho, Arizona, 1707",
  "favoriteFruit": "banana"
 },
 {
  "_id": "58f9a196c020af14f6726d3a",
  "index": 1,
  "guid": "d1695e0f-2d05-465e-8e14-eca9ad64c426",
  "isActive": false,
  "balance": "$1,194.79",
  "picture": "http://placehold.it/32x32",
  "age": 30,
  "eyeColor": "green",
  "name": {
   "first": "Norton",
   "last": "Curtis"
  },
  "company": "RECRISYS",
  "email": "norton.curtis@recrisys.tv",
  "phone": "+1 (850) 571-3013",
  "address": "106 Bliss Terrace, Vandiver, Mississippi, 9292",
  "favoriteFruit": "strawberry"
 },
 {
  "_id": "58f9a196d46f3d10560759bd",
  "index": 2,
  "guid": "bf810ee3-3bc4-44e0-8056-3ac3815d2887",
  "isActive": true,
  "balance": "$2,259.39",
  "picture": "http://placehold.it/32x32",
  "age": 38,
  "eyeColor": "brown",
  "name": {
   "first": "Zamora",
   "last": "Weber"
  },
  "company": "PERMADYNE",
  "email": "zamora.weber@permadyne.co.uk",
  "phone": "+1 (929) 591-2437",
  "address": "787 Crystal Street, Williston, Wisconsin, 6408",
  "favoriteFruit": "strawberry"
 },
 {
  "_id": "58f9a196fe6014ff5fd07cb5",
  "index": 3,
  "guid": "e5cfcd2e-2911-4293-9a0f-3a53374ea1d9",
  "isActive": true,
  "balance": "$3,019.42",
  "picture": "http://placehold.it/32x32",
  "age": 25,
  "eyeColor": "blue",
  "name": {
   "first": "Barnes",
   "last": "Pickett"
  },
  "company": "RECRISYS",
  "email": "barnes.pickett@RECRISYS.info",
  "phone": "+1 (804) 532-3235",
  "address": "500 Milton Street, Nadine, Kansas, 8781",
  "favoriteFruit": "apple"
 },
 {
  "_id": "58f9a196361f66d65c9b39f8",
  "index": 4,
  "guid": "80ca8651-5edf-4d11-bb09-688f654ff3ad",
  "isActive": true,
  "balance": "$3,334.51",
  "picture": "http://placehold.it/32x32",
  "age": 33,
  "eyeColor": "brown",
  "name": {
   "first": "Cohen",
   "last": "James"
  },
  "company": "COMSTAR",
  "email": "cohen.james@comvene.name",
  "phone": "+1 (953) 454-3801",
  "address": "230 Lefferts Avenue, Navarre, Tennessee, 3443",
  "favoriteFruit": "strawberry"
 },
 {
  "_id": "58f9a19607f1cc3aafc21c5b",
  "index": 5,
  "guid": "df311b09-081c-4a31-b30f-a87700728244",
  "isActive": false,
  "balance": "$2,046.56",
  "picture": "http://placehold.it/32x32",
  "age": 32,
  "eyeColor": "green",
  "name": {
   "first": "Vanessa",
   "last": "Sanchez"
  },
  "company": "COMSTAR",
  "email": "vanessa.sanchez@magmina.biz",
  "phone": "+1 (877) 430-2487",
  "address": "665 Norfolk Street, Bawcomville, Kentucky, 8056",
  "favoriteFruit": "banana"
 }
]

Now Here is an interactor class:
class Interactor: NSObject {
    func findListData() {
        //Find data
        let file = FileReader();
        //We can set default argument in parms it self - a Swift feature
       // file.readJsonFile(name:"company", exten: "json")
        if let data = file.readJsonFile(name:"company") {
            let myArr:NSArray? = ParseData(aObject: data);
            if myArr != nil {
                presenter?.foundList(aList: myArr);
            }
        }
    }
    //MARK: Model parse
    func ParseData(aObject:Any) -> NSArray? {
        let myArr : NSMutableArray = NSMutableArray();
        if aObject is NSArray {
            for  mydata in aObject as! NSArray {
                let data = mydata as! NSDictionary
                let mymodel : CompanyModel  = CompanyModel.init(fname: data.value(forKeyPath:"name.first") as! String, lname: data.value(forKeyPath:"name.last") as! String, company: data.value(forKey:"company") as! String)
                myArr.add(mymodel);
            }
            return myArr;
        }
        return nil;
    }
    
}

Here is a file reader class:
class FileReader:NSObject {
    func readJsonFile(name:String, exten:String="json") -> Any? {
        do {
            if let file = Bundle.main.url(forResource:name, withExtension:exten) {
                let data = try Data(contentsOf: file)
                let json = try JSONSerialization.jsonObject(with: data, options: [])
                if let object = json as? [String: Any] {
                    // json is a dictionary
                    // print(object)
                } else if let object = json as? [Any] {
                    // json is an array
                    // print(object)
                    return object;
                } else {
                    print("JSON is invalid")
                }
            } else {
                print("no file")
            }
        } catch {
            print(error.localizedDescription)
        }
        return nil;
    }
}

To transform data in to model we have one company-model class:
class CompanyModel : NSObject {
    var fName : String = ""
    var lName : String = ""
    var company : String = ""
    init(fname:String,lname:String,company:String) {
        self.fName = fname
        self.lName = lname
        self.company = company
    }
}

There are some changes which we have to do in order to show the data. In presenter class, we will replace “foundList” method with below code:
func foundList(aList:NSArray?) {
        if(aList != nil) {
            userInterface?.reloadList(alist: aList)
        }
        else {
            userInterface?.showNoContenctView()
        }
    }

Now we want to show name, in view It is divided in two partition First name and Last name.We will add one method which can return these two in a single entity. To do so we will add one function in a model class.
var name : String { get {
        return "\(fName) \(lName)"
        }
    }


Now here is a code for UIView:
extension  ViewController: UITableViewDataSource,UITableViewDelegate {
    //MARK:- TableView methods
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return myArr!.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: ListEntryCellIdentifier, for: indexPath as IndexPath) as! listCell
        let myData:CompanyModel = myArr!.object(at: indexPath.row) as! CompanyModel
        cell.title.text = String(myData.name)
        cell.companyName.text = String(myData.company)
        cell.selectionStyle = UITableViewCellSelectionStyle.none
        return cell
    }
    //MARK: ViewInterface implementation
    func reloadList(alist:NSArray?) {
        myArr = alist
        if myArr != nil {
            DispatchQueue.main.async {
                self.listTableView?.reloadData();
            }
        }
    }
    func showNoContenctView() {
        let alert = UIAlertController.init(title: "VIPER", message: "No content to show", preferredStyle:.alert)
        let okAction = UIAlertAction.init(title: "OK", style: UIAlertActionStyle.default, handler: nil)
        alert.addAction(okAction)
        self.present(alert, animated:true, completion: nil)
    }
}


At this point of time there is no major code in presenter, now we will change the requirement and see how presenter could be used.

Time for twist: We want to sort the data and show the list as per their company and want to show the balance.

Anticipated output:


VIPER: Interactor and Entity

To do so we need to alter data in model, presenter and UIView:
class model code change:
 init(fname:String,lname:String,company:String,balance:String) {
        self.fName = fname
        self.lName = lname
        self.company = company
        self.balance = balance
    }

Here is a change in code of presenter:
 func foundList(aList:NSArray?) {
        let sortedArray:NSArray? = self.SortCompanyList(aList: aList)
        if(sortedArray != nil) {
            userInterface?.reloadList(alist: sortedArray);
        } else {
            userInterface?.showNoContenctView()
        }
    }
//This function is used to sort the data as we require.
    func SortCompanyList(aList:NSArray?) -> NSArray? {
        let sortedArray: NSMutableArray = []
        if(aList != nil) {
            let listOfCompany:NSArray? = aList?.value(forKeyPath:"@distinctUnionOfObjects.company") as? NSArray
            if(listOfCompany != nil) {
                for companyName in listOfCompany! {
                    let predicate = NSPredicate(format: "%K = %@", "company", companyName as! NSObject)
                    let filteredContacts = aList?.filtered(using: predicate)
                    if ((filteredContacts?.count)! > 0) {
                        let sortedDict = NSDictionary.init(object: filteredContacts!, forKey:companyName as! NSCopying)
                        sortedArray.add(sortedDict)
                    }
                }
            }
            
        }
        return (sortedArray.count > 0) ? sortedArray : nil 
    }

Now here is a code for UIView:
extension  ViewController: UITableViewDataSource,UITableViewDelegate{
    //MARK:- TableView methods
     func numberOfSections(in tableView: UITableView) -> Int {
        return myArr!.count
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
         let dictSection:NSDictionary = (myArr?.object(at:section) as! NSDictionary)
        return (dictSection.object(forKey:dictSection.allKeys.first!) as! NSArray).count
    }
    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        let dictSection:NSDictionary = (myArr?.object(at:section) as! NSDictionary)
        let title:String = " \(dictSection.allKeys.first as! String)"
        return title
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: cListEntryCellIdentifier, for: indexPath as IndexPath) as! listCell
        //Fetch model
        let dictSection:NSDictionary = (myArr?.object(at: indexPath.section) as! NSDictionary)
        let myData:CompanyModel = (dictSection.object(forKey:dictSection.allKeys.first!) as! NSArray).object(at: indexPath.row) as! CompanyModel
        //Set model data
        cell.title.text = String(myData.name)
        cell.companyName.text = String(myData.balance)       
        cell.selectionStyle = UITableViewCellSelectionStyle.none
        return cell
    }
    //MARK: ViewInterface implementation
    func reloadList(alist:NSArray?) {
        myArr = alist;
        if myArr != nil {
            DispatchQueue.main.async {
                self.listTableView?.reloadData();
            }
        }
    }
    func showNoContenctView(){
        let alert = UIAlertController.init(title: "VIPER", message: "No content to show", preferredStyle:.alert)
        let okAction = UIAlertAction.init(title: "OK", style: UIAlertActionStyle.default, handler: nil)
        alert.addAction(okAction)
        self.present(alert, animated:true, completion: nil)
    }
    
}


This is the end of second VIPER post, In next post we will explore router/wireframe code and  unit test case for the same app.

Wednesday, June 14, 2017

VIPER an iOS architecture

I have been practicing VIPER architecture since one year and I found lots of ups and down while using it.
In this blog I will try to explain and simplify VIPER architecture.
Here are the two images which you could see when you search for VIPER architecture. 

VIPER an iOS architecture


VIPER an iOS architecture


Both are almost same and right. It is on you and use cases that which one you could choose to use. We will use both images at various time as we proceed.

Why VIPER?
Most of the iOS Apps follows MVC pattern and since much of the application code cannot fit in model or view are ended up in ViewController which makes our ViewController the Massive View Controller. VIPER could focus to reduce the load of ViewController.
Testing was never a major part of making iOS Apps and it is too difficult to test with various architectures but VIPER helps a lot in this area too.
We can divide code on basis of functionality like login, register, view account etc.

What is VIPER?
Here what VIPER stands for:
V-> View
I-> Interactor
P-> presenter
E-> Entity
R-> Router
Here is a general diagram which helps you to understand the flow.

VIPER Flow Diagram



View: One super secret is Your View = ViewController class + Interface View. It is a passive and can request presenter to update itself. The presenter does not know about any existence of UI elements like UIButton or UILabel, but it maintains the content. Till now what you do in ViewController class is your View and we will practice to reduce its load so now on View Controller has to worry only about showing content. And other responsibilities we will pass to presenter, interactor and so on.

Presenter: It consist the logic to drive the UI. And also handles the events passed by View and interactor. Lets explore this both using example.


Use case: We have a ViewController and we want to show some content in the view, however this is our first step we do not have any content to show, so we would show only popup with no content.

Prior code:
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
            self.updateView()
    }
    func updateView() {
         var myArray:NSArray? = nil ;
        //now we would call web service or db method to load data so that myArray != nil
        if(myArray != nil) {
            //Do change to make it appropriate with regards to view, like change array into model - entity form.
        }
        else {
            let alert = UIAlertController.init(title: "VIPER", message: "No content to show", preferredStyle:.alert)
            let okAction = UIAlertAction.init(title: "OK", style: UIAlertActionStyle.default, handler: nil)
            alert.addAction(okAction)
            self.present(alert, animated:true, completion: nil)
        }
    }

}

After adding presenter:

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
            presenter.updateView()
    }
    func showNoContenctView(){
        let alert = UIAlertController.init(title: "VIPER", message: "No content to show", preferredStyle:.alert)
        let okAction = UIAlertAction.init(title: "OK", style: UIAlertActionStyle.default, handler: nil)
        alert.addAction(okAction)
        self.present(alert, animated:true, completion: nil)
    }

}
class Presenter:NSObject {
    func updateView() {
        //ask interactor for data.
        interactor.findListData()
      }
   
    //This method will be called by interactor once interactor gets the data
    func foundList(aList:NSArray?) {
        if(aList != nil) {
            //if list != nil //we would be doing some data formation before passing this to the view.
        }
        else {
            userInterface?.showNoContenctView();
        }
    }
    
}

Draft:1 This is the end of first draft, in next post we will learn about interactor and entity.

Tuesday, February 23, 2016

An open-sourced iOS imgur api example - GitHub

Imgur is the best place to share and enjoy the most awesome images on the Internet. Every day, millions of people use Imgur to be entertained.


Here is all the information for its API and to start all you need is API key.

Here are the required thing to learn to use Imgur API.









You can Download Full code From GitHUB

Sunday, November 1, 2015

Colour-Memory 4*4 grid project

The goal of this work sample is to construct a sample memory game called ”Colour Memory”. The game board consists of a 4x4 grid with 8 pairs of color cards.

 Here is a list of things I used to create this sample.

1) Use of sqlite database  and interaction class 
2) subclassing of UITableViewCell
3) subclassing of UIButton
4) Use of Auto Layout in iOS


UIButton subclassing is used to store the state of that button
and used to store the image name that we need to set as a image when user taps on that button.
It also contain animation code of flip view from left to right and right to left.
Here is a code to flip the UIButton and show image.

You can find this code in below given link.
Name of the file is ColorUIButton
 -(void)showButtton  
 {  
 self.userInteractionEnabled = false;  
 [UIView transitionWithView:self duration:0.3 options:UIViewAnimationOptionTransitionFlipFromRight animations:^{  
 //code to change the image of UIButton  
 } completion:^(BOOL finished) {  
 self.userInteractionEnabled = true;  
 }];  
 }  







UITableViewCell is used to handle the row of 4 UIButtons
 It handle all the interaction done on UIButton.

You can find this code in below given link.
Name of the file is ColorCell


















Download full code from GitHub

Saturday, October 31, 2015

Twitter Integration in iOS

Twitter Integration using SLRequest 

 1) Ask user to access its twitter account

  ACAccountStore *accountStore = [[ACAccountStore alloc] init];  
   ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];  
   [accountStore requestAccessToAccountsWithType:accountType options:nil completion:^(BOOL granted, NSError *error) {  
     if(granted) {  
            //User allowed to access account  
     }}];  

2) Get all twitter accounts from list

 ACAccountStore *store = [[ACAccountStore alloc] init];  
   ACAccountType *AccountType = [store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];  
  NSArray *accountsArray = [store accountsWithAccountType:AccountType];  

3)get particular Account from Accounts array.

 -(ACAccount *)getTwitterAccount:(NSString *)aStrUserName  
 {  
   ACAccountStore *store = [[ACAccountStore alloc] init];  
   ACAccountType *AccountType = [store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];  
   __weak ACAccount *selAccount = nil;  
   NSArray *accountsArray = [store accountsWithAccountType:AccountType];  
   for (ACAccount *myaccount in accountsArray) {  
     if([myaccount.username.lowercaseString isEqualToString:aStrUserName.lowercaseString])  
     {  
       selAccount = myaccount;  
       break;  
     }  
   }  
   return selAccount;  
 }  

Thursday, October 29, 2015

How to add image in UINavigationBar in iPhone app

How to add image in UINavigationBar in iPhone app

 +(void)setNavigationBarAppearance{  
   [[UINavigationBar appearance]setBackgroundImage:[UIImage imageNamed:@"image name.png"] forBarMetrics:UIBarMetricsDefault];  
   [[UINavigationBar appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:  
                              [UIColor whiteColor], NSForegroundColorAttributeName,  
                              [UIFont fontWithName:@"Font name" size:17.0], NSFontAttributeName,nil]];  
 }  

To set title view of UINavigationBar use below code

 viewController.navigationItem.titleView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"yourimage.png"]];  


How to disable back swipe gesture in UINavigationController on iOS
From iOS 7 Apple added a new default navigation behavior. You can swipe from the left border of the screen to go back on the navigation stack.
So, It is possible to disable this new gesture in UINavigationController.
Just add this online code and thats it.

  if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)])  
     [self.navigationController.view removeGestureRecognizer:self.navigationController.interactivePopGestureRecognizer];  

OR

  if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)])  
   self.navigationController.interactivePopGestureRecognizer.enabled = false;  


The edgesForExtendedLayout property, together with the extendedLayoutIncludesOpaqueBars property, determines whether or not view controllers' views underlap top and bottom bars (navigation bar, toolbar)
Extenedges- iOS
This is useful when you are using Storyboard and UINavigationBar & you want to start counting frame after UINavigationBar ends with autolayout.
so just select checkbox of Extenedges - Under top bars and thats it.