Sunday, June 25, 2017

Closures Part - 2 (Swift)

4:10 AM Posted by CHANDAN MAKHIJA No comments
This is second part of closures, if you haven't gone thorough first part then please go through it before reading this.
In this part you will learn about completion handlers, when to use@escaping and trailing closure,so lets begin with it.

Trailing Closures

A trailing closure can be used only if a function requires a closure as the final argument/parameter. You may trail (to follow behind) the closure argument parameter section. In other words, the final parameter is separated from the normal function parameter block.
Okay, now it’s time to create a function that sums a range of values. Of course, we are going to add timesTenFunc or timesTenClosure as the final parameter. 
func sum(from: Int, to: Int, closure: (Int) -> (Int)) -> Int {

var sum = 0

for i in from...to {

sum += closure(i)

}

return sum

}

// Normal Closure calling

sum(from: 0, to: 10, closure: { number in return number * 10 })


// Trailing Closure Longer Version

sum(from: 0, to: 10) { (number) in

return number * 10

}

// Trailing Closure Shorter Version

sum(from: 0, to: 10) { return $0 * 10}

// Trailing Closure Extremely Short Version

sum(from: 0, to: 10) { $0 * 10 }


So, what’s the advantage of using trailing closures? Well, it is particularly useful when your closure expression is longer than just simply multiplying values or when you are using completion handlers, which I will talk about them soon in this article. Trailing closures make code readable and eye friendly. You can use normal closure, a trailing closure is optional, but most developers love/use it.

Completion Handler

There are times you put a closure as one of the parameters, but you only want to execute the closure after the function returns. For example when you want to notify user after downloading a file from the URL, we use completion handler in this case.
// Create Function

func downloadFileFromURL(url: NSURL, completionHandler: (Bool) -> Void) {

// NSURL logic code & download. (return false/true)
 completionHandler(true)

// Download has been completed
}

Surprisingly, even before we call the function downloadFileFromURL, we’ve provided a default parameter to the completionHandler block by defining it as true only if the networking logic has successfully gone through. So, when you run the function, the only parameter you need to fill up is url and you can notify the user based on whether the completionBlock is true or false 
// Run function

downloadFileFromURL(url: NSURL(string: "abc")!, completionHandler: {

isSuccessful -> Void in

if isSuccessful {

print("You've downloaded")

} else {
print("Unexpected error encountered")

}
})


I have arbitrarily called the predefined the name of the parameter (true/false) as isSuccessful. The cool thing is, again, isSuccessfulalready has its own value because we predefined while creating the function. However, please remember that isSuccessful is only defined after going through the network logic.

In real life situation when you try to fetch data from Firebase/Facebook, you will always ask to put something like
fetchProfileImage() { (imageFile, name, error) in

if error == nil {
}

// put into UIImage with imageFile/name
}


Escaping/Non Escaping Closures

There are 2 types of closures, Escaping closure and non Escaping closures.
I will explain you one by one


   - Non Escaping Closure

      The lifecycle of a non-escaping closure is simple:

1.    Pass a closure into a function
2.    The function runs the closure (or not)
3.    The function returns



Notice the closure has not escaped the body of the function. When the function ends, the passed-in closure goes out of scope and there were no additional references made to the closure.
If you remember your memory management, you might say the retains and releases are balanced; the closure object’s retain count after the function returns is the same as it was before the function was called.



- Escaping Closures
You can probably guess what “escaping closure” means now. Inside the function, you can still run the closure (or not); the extra bit is the closure is stored some place that will outlive the function. There are several ways to have a closure escape its containing function.
Asynchronous execution: If you execute the closure asynchronously on a dispatch queue, the queue will hold onto the closure for you. You have no idea when the closure will be executed and there’s no guarantee it will complete before the function returns.
Storage: Storing the closure to a global variable, property, or any other bit of storage that lives on past the function call means the closure has also escaped.



Saturday, May 20, 2017

How to check for Network Connection in your IOS apps

9:21 AM Posted by CHANDAN MAKHIJA No comments
IOS apps need to handle network connectivity very carefully. An iOS user may travel from a Wifi connection to a 3G connection to a dead spot all while using your app. For this reason, Apple is extremely strict about developers handling network connectivity problems elegantly. They will outright reject your app if it errors out due to no network.

Why doesn’t Apple do it for me? 
Since this is such a common requirement, you must be wondering why IOS (even IOS5) doesn’t handle this for the app. All Apple has to do is allow developers to add a .plist setting called “NetworkRequired=1” and iOS should handle the error for you. Since, all network calls will go through iOS SDK stack, it should be able to catch the errors right?
The most obvious reason that comes to my mind about why they want you to handle the issue is – Only your App knows what to do when a network failure occurs.
  • Maybe the network failure is something which you don’t care about and the app can continue working.
  • Maybe it is a critical error and you need to notify the user about it.
  • Maybe your app can afford to retry the operation based on the nature of the network API call.
  • (BOOL) connectedToNetwork  is used when we just want to check for a network connection and not notify the user if an error occurs.
  • (BOOL) checkInternet is the same but automatically shows user an error message to notify him if no internet connection is present.

So, it makes sense for your app to handle the network issues.
The Solution :
So, the solution is very simple. First make sure that you have a helper class that you use to make every single network/API call. This way the network/API code is in one place. Easier to maintain and easier to add error handling

In Resource Manager, we used the below two functions to check for internet.
There is no rocket science here. In fact this code is available in one of Apple’s own samples and we have just used it in our app.
- (BOOL) connectedToNetwork
{
 Reachability *r = [Reachability reachabilityWithHostName:@"www.google.com"];
 NetworkStatus internetStatus = [r currentReachabilityStatus];
 BOOL internet;
 if ((internetStatus != ReachableViaWiFi) && (internetStatus != ReachableViaWWAN)) {
  internet = NO;
 } else {
  internet = YES;
 }
 return internet;
} 

-(BOOL) checkInternet
{
 //Make sure we have internet connectivity
 if([self connectedToNetwork] != YES)
 {
  [self showMessage: @"No network connection found. An Internet connection is required for this application to work"
    withTitle:@"No Network Connectivity!"];
  return NO;
 }
 else {
  return YES;
 }
}

Saturday, April 29, 2017

iOS Design Patterns: MVC and MVVM

11:15 AM Posted by CHANDAN MAKHIJA No comments
iOS was first released in 2007, since then it has implemented Model-View-Controller (MVC) development design pattern. This design pattern is a common way to organize code so that it is reusable and more easily extensible. 
In this post, we are going to look closer at the existing iOS MVC pattern variation and offer an alternative, and perhaps better, pattern for iOS development.

Introducing MVVM
One issue facing iOS developers is how to deal with major iOS updates for existing projects. More specifically, how to implement UI/UX changes as iOS evolves. Because iOS uses a combined view-controller design, this task can require a greater level of effort than should be necessary. Here’s why: because the view and controller are coupled, an iOS view-controller class will usually contain both UI logic and business logic. This means that changes in the way the view is presented (UI logic) will usually also require changes to business logic within the same view controller class.
Further, as view controller classes implement increasingly complex UI requirements, the amount of business-logic code also tends to grow within the same view controller class. This, is turn, typically results in large, unwieldy, and difficult-to-read view controller classes.
Wouldn’t it be better to have thin, flexible, easy-to-read view controller classes in iOS?

The MVVM Design Pattern
The “Model-View ViewModel” design pattern, or “MVVM”, is similar to the MVC as implemented in iOS, but provides better decoupling of the UI and business logic. This decoupling results in thin, flexible, and easy-to-read view controller classes in iOS
Business Logic and workflows are contained in ViewModel and all UI related logic is there in View-Controllers, and knows nothing about business logic.
MVVM is built around three fundamental parts: data model, view/view-controller, and viewModel:

1) Data Model
Just like in the MVC design pattern, the MVVM data model is a class that declares properties for managing business data.
2) ViewModel
The viewModel is at the heart of the MVVM design pattern and provides the connection between the business logic and the view/view controller. The view (UI) responds to user input by passing input data (defined by the model) to the viewModel. In turn, the viewModel evaluates the input data and responds with an appropriate UI presentation according business logic workflow.
3) View/View Controller
The view/view controller is the context (i.e. the view controller class) that presents user interface elements. It contains no business logic


Advantages of MVVM Design Pattern

Thin view controllers that are easily debugged
In MVVM, view controllers are concerned only with the UI. MVVM UI encapsulation means finding and fixing UI issues is usually a straightforward process that no longer involves digging through business logic trying to locate the root cause of a particular bug.
Flexible business logic and work flows
Adding and modifying workflows (e.g. which view shows when) is done very quickly in the MVVM design pattern. MVVM UI/business logic decoupling means changes can usually be done with simple one or two line changes in the viewModel.
Code reuse
Most init, setup, and view presentation methods are implemented in the viewModel class. As such, each new view controller shares those methods, which means no redundant view controller code.

Sunday, April 16, 2017

Scan QR Code / Bar Code Using AVFoundation Framework (Objective c)

10:54 PM Posted by CHANDAN MAKHIJA No comments
AV Foundation is the full featured framework for working with time-based audiovisual media on iOS, macOS, watchOS and tvOS. Using AV Foundation, you can easily play, create, and edit QuickTime movies and MPEG-4 files, play HLS streams, and build powerful media functionality into your apps.

AVFoundation incorporates,  the ability to discover and read bar codes in real-time. Any barcode scanning, including QR codes, is totally based on video capturing, that’s why AVFoundation framework supports the barcode reading feature. Keep this info on mind, as it’s the starting point for the entire application.

First of all add UIView view, which is going to be the container for the preview layer of the video captured by the device.

Here is how the demo application is going to work:

Add the camera button on the UIViewController. When you will click on this button a UIView will be loaded that will contain the preview of recording. When you will start recording any Barcode , it will capture it and display the information captured on UITextField.

Also, a sound effect (a beep sound) is being played every time a QR code has been successfully read to make our app more vivid and interactive.

Note that this application cannot be tested on the Simulator, neither to a device without a camera, as everything is based on real-time video capturing. Therefore, you’ll need to connect your device and run it there if you want to see the application live.

First of all make XIB that contains a UIView with Black BackGround, as shown below





 Make a class named "QRScanView"

Add following code in "QRScanView.h"


#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>

@interface QRScanView : UIView <AVCaptureMetadataOutputObjectsDelegate>

// connect your Xib here
@property (weak, nonatomic) IBOutlet UIView *scanView;

@property (nonatomic, strong) AVCaptureSession *captureSession;
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *videoPreviewLayer;

@property  BOOL isReading;

@property void(^barCodeScanned)(NSString*);

+ (instancetype) loadScanner;

- (void)showScanner:(UIViewController*) vc;
- (void) getScannedValue:(void(^)(NSString* message))callback;


@end


Add following code in "QRScanView.m"


#import "QRScanView.h"

static QRScanView* sSharedInstance;
static QRScanView* _scanner ;

@interface QRScanView()
{
    NSString* _serviceTag;
}

@end

@implementation QRScanView

+ (instancetype) loadScanner
{
    if(!sSharedInstance)
    {
        // load your xib on UIView here
        sSharedInstance = [[[NSBundle mainBundle] loadNibNamed:@"QRScanView" owner:sSharedInstance options:nil] lastObject];
    }
    
    return  sSharedInstance;
}

- (void)showScanner:(UIViewController*) vc
{
    sSharedInstance.isReading = NO;
    sSharedInstance.captureSession = nil;
    sSharedInstance.center = CGPointMake(vc.view.frame.size.width  / 2,
                                  vc.view.frame.size.height / 2);
    sSharedInstance.layer.borderWidth = 1.0f;
    sSharedInstance.layer.borderColor = [UIColor lightGrayColor].CGColor;
    
    [sSharedInstance startReading];
    
    [vc.view addSubview:sSharedInstance];
}

- (void) startReading
{
    NSError *error;
    
    AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    
    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
    if (!input)
    {
        NSLog(@"%@", [error localizedDescription]);
    
    }
    
    _captureSession = [[AVCaptureSession alloc] init];
    [_captureSession addInput:input];
    
    AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init];
    [_captureSession addOutput:captureMetadataOutput];
    
    dispatch_queue_t dispatchQueue;
    dispatchQueue = dispatch_queue_create("myQueue", NULL);
    
    [captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatchQueue];
    
     // include all types of barcode here
    [captureMetadataOutput setMetadataObjectTypes:[NSArray                 arrayWithObjects:AVMetadataObjectTypeQRCode, AVMetadataObjectTypeFace, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeUPCECode,AVMetadataObjectTypeAztecCode, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeITF14Code,AVMetadataObjectTypeCode39Code, AVMetadataObjectTypeCode93Code, AVMetadataObjectTypePDF417Code, AVMetadataObjectTypeCode128Code, AVMetadataObjectTypeDataMatrixCode,AVMetadataObjectTypeCode39Mod43Code,AVMetadataObjectTypeInterleaved2of5Code, nil]];
    
    _videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
    [_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
    [_videoPreviewLayer setFrame:self.scanView.layer.bounds];
    [self.scanView.layer addSublayer:_videoPreviewLayer];
    
    [_captureSession startRunning];
    
}

- (void) stopReading
{
    [_captureSession stopRunning];
    _captureSession = nil;
    
    [_videoPreviewLayer removeFromSuperlayer];
    
    // remove Xib from view here
    [self removeFromSuperview];
    
    self.barCodeScanned(_serviceTag);
}

// get scanned value here
- (void) getScannedValue:(void(^)(NSString* message))callback
{
    self.barCodeScanned = callback;
}

// Delegate methods for AVCaptureMetadataOutputObjects
- (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
    if (metadataObjects != nil && [metadataObjects count] > 0)
    {
        AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjects objectAtIndex:0];
        
        _serviceTag = [metadataObj stringValue];
        
        [self performSelectorOnMainThread:@selector(stopReading) withObject:nil waitUntilDone:NO];
       
        self.isReading = NO;
    }
}


@end



Now import "BarcodeScan.h" file in you ViewController

On IBAction of  button click, call the method of "QRScanView" class like this


- (IBAction)scanCodeBtnPressed:(id)sender
{
    QRScanView* scanner = [QRScanView loadScanner];

    self.scanCodeBtn.selected = !self.scanCodeBtn.isSelected;
    
    if(self.scanCodeBtn.selected)
        [scanner showScanner:self];
    
    [scanner getScannedValue:^(NSString *message) {
        //display scanner message on UITextField
        UITextField* textField = (UITextField*)[self.view viewWithTag:EServiceTag];
        textField.text = message;
    }];

}