Tuesday, April 28, 2015

Learn Python by example


Create a simple class in Python


class Employee(object):
"""Encapsulate employee information here"""
def __init__(self, name, age):
super(Employee, self).__init__()
self.name = name
self.age = age

def printDetails(self):
print('Name is ' + self.name)
print('Age is ' + str(self.age))

def __del__(self):
class_name = self.__class__.__name__
print(class_name + ' destroyed')

tempEmp = Employee('Krishnan', 35)
tempEmp.printDetails()

All methods, have a default first argument of self. __init__ is synonymous to constructors in C++/Java/C# world. Initialize your properties in init method

__del__ is synonymous to destructor. Dereference your objects here

You can access the properties of the class, from within the class using "self" keyword. Although you'll be able to access the same properties from outside the class like the following
print('Name of employee: ' + tempEmp.name)

I'd prefer few other ways of doing the same
getattr(obj, name[, default]) - get an attribute
hasattr(obj,name) - check to see if an attribute is defined
setattr(obj,name,value) - Set value on an attribute, if attribute does not exist, it is created on this instance
delattr(obj, name) - Delete's the attribute from the instance

class Employee(object):
"""Encapsulate employee information here"""
def __init__(self, name, age):
super(Employee, self).__init__()
self.name = name
self.age = age

def printDetails(self):
print('Name is ' + self.name)
print('Age is ' + str(self.age))

tempEmp = Employee('Krishnan', 35)
if hasattr(tempEmp, 'age'):
print('Age of employee is ' + str(getattr(tempEmp, 'age', 10)))

if hasattr(tempEmp, 'salary') == False:
setattr(tempEmp, 'salary', 1000000)

if hasattr(tempEmp, 'salary'):
print('Salary of employee is ' + str(getattr(tempEmp, 'salary', 0)))

Garbage collection


Garbage Collection in Python is simple and easy to follow. When an object is created, assigned a new name or added to a container, reference count is increased. When an object is removed using 'del' keyword or goes out of scope, its reference count is decreased. When the count reaches '0', it will be garbage collected


Inheritence

Sample for simple inheritance in Python is shown below

class Employee(object):
"""Encapsulate employee information here"""
def __init__(self, name, age):
super(Employee, self).__init__()
self.name = name
self.age = age

def printDetails(self):
print('Name is ' + self.name)
print('Age is ' + str(self.age))

def __del__(self):
class_name = self.__class__.__name__
print(class_name + ' destroyed')

class Manager(Employee):
"""docstring for Manager"""
def __init__(self, name, age, department):
super(Manager, self).__init__(name, age)
self.department = department

def printDetails(self):
super(Manager, self).printDetails()
print('Works for: ' + self.department)

def __del__(self):
class_name = self.__class__.__name__
print(class_name + ' destroyed')

tempEmp = Manager('Krishnan', 35, 'IT')
tempEmp.printDetails()
if hasattr(tempEmp, 'age'):
print('Age of employee is ' + str(getattr(tempEmp, 'age', 10)))

if hasattr(tempEmp, 'salary') == False:
setattr(tempEmp, 'salary', 1000000)

if hasattr(tempEmp, 'salary'):
print('Salary of employee is ' + str(getattr(tempEmp, 'salary', 0)))

We can easily extend this to Multi-level inheritence. Note how super class methods are invoked. If you need to make any decision based on instance methods, you could use any of the following methods

isinstance(obj, Class) - Checks to see if obj is an instance of 'Class'
issubclass(sub, sup) - Checks to see of 'sub' is a subclass of super class'sup'

Method printDetails in Manager is the overriden method, hence we need to do super.printDetails.

If you are wondering how to hide properties in a class use '__' syntax. In the following example, you'll notice employeeIdentificationCode in Employee class that is a private property. It cannot be accessed anywhere but Employee class. It will not be accessible in Manager class too.

#! /Library/Frameworks/Python.framework/Versions/3.4/bin/python3

class Employee(object):
"""Encapsulate employee information here"""
__employeeIdentificationCode = 0
def __init__(self, name, age, empNo):
super(Employee, self).__init__()
self.name = name
self.age = age
self.empNo = empNo
self.__employeeIdentificationCode = empNo + 10


def printDetails(self):
print('Emp No: ' + str(self.empNo))
print('Name is ' + self.name)
print('Age is ' + str(self.age))
print('Personal Identification Code: ' + str(self.__employeeIdentificationCode))


def __del__(self):
class_name = self.__class__.__name__
print(class_name + ' destroyed')

class Manager(Employee):
"""docstring for Manager"""
def __init__(self, name, age, empNo, department):
super(Manager, self).__init__(name, age, empNo)
self.department = department

def printDetails(self):
super(Manager, self).printDetails()
print('Works for: ' + self.department)

def __del__(self):
class_name = self.__class__.__name__
print(class_name + ' destroyed')

tempEmp = Manager('Krishnan', 35, 100,'IT')
tempEmp.printDetails()
if hasattr(tempEmp, 'age'):
print('Age of employee is ' + str(getattr(tempEmp, 'age', 10)))

if hasattr(tempEmp, 'salary') == False:
setattr(tempEmp, 'salary', 1000000)

if hasattr(tempEmp, 'salary'):
print('Salary of employee is ' + str(getattr(tempEmp, 'salary', 0)))


Operator Overloading

You can do operator overloading by overriding methods like __add__ and __sub__

Class attributes

More often then not, we'll need static variables in class. Here' how we do it. Check out variable 'VectorCount' in the sample below

#! /Library/Frameworks/Python.framework/Versions/3.4/bin/python3

class Vector(object):
"""docstring for Vector"""
vectorCount = 0

def __init__(self, real, imaginary):
super(Vector, self).__init__()
self.real = real
self.imaginary = imaginary
Vector.vectorCount += 1

def showEquation(self):
print('Equation ' + str(Vector.vectorCount))
print (str(self.real) + 'x + ' + str(self.imaginary))

def __del__(self):
class_name = self.__class__.__name__
print(class_name + ' destroyed')

vect1 = Vector(10, 11)
vect1.showEquation()

vect2 = Vector(9, 12)
vect2.showEquation()

vect3 = Vector(8, 13)
vect3.showEquation()

vect4 = Vector(7, 14)
vect4.showEquation()


Class information/introspection

There are a lot of times, we will like to do some introspection on a class. Be it a high level documentation, dump of a class, etc. If you ever wanted such, here's how we do it
#! /Library/Frameworks/Python.framework/Versions/3.4/bin/python3

class Vector(object):
"""docstring for Vector"""
vectorCount = 0
__vectorID = 0

def __init__(self, real, imaginary):
super(Vector, self).__init__()
self.real = real
self.imaginary = imaginary
Vector.vectorCount += 1
self.__vectorID += 1

def showEquation(self):
print('Equation ' + str(Vector.vectorCount))
print (str(self.real) + 'x + ' + str(self.imaginary))

def __del__(self):
class_name = self.__class__.__name__
print(class_name + ' destroyed')


def printClassInformation():
print(Vector.__doc__)
print('Class under introspection: ' + Vector.__name__)
print('Class information: ' + str(Vector.__dict__))

vect1 = Vector(10, 11)
vect1.showEquation()

vect2 = Vector(9, 12)
vect2.showEquation()

vect3 = Vector(8, 13)
vect3.showEquation()

vect4 = Vector(7, 14)
vect4.showEquation()

printClassInformation()

__doc__ prints the comments in the class
__name__ prints the name of the class
__dict__ prints a dump of class. Try out a dump of a class with private properties and class properties. You are in for surprise
__bases__ prints inheritence hierarchy of the class
__module__ prints the module/function information

File operations

#!/usr/bin/python
import os

#FILE_NAME='Deploy_ios_application_to_device.txt'
FILE_NAME='Sample.txt'
# Identify current location
os.getcwd()
os.chdir('/Users/sriramramakrishnan/Private')

try:
# open the file that needs to be read
data = open(FILE_NAME)

# read line by line, until end
for line in data:
line = line.strip()
print(line)

# after reading the file, make sure you close it
data.close()
# there it ends
except IOError as err:
print('ERROR: failed to open file')
print('Error description: ' + str(err))
finally:
if 'data 'in locals():
print('File is open and should be closed!')
data.close()

Sunday, April 26, 2015

WebView in Library

//
//  MyTableViewFAQViewController.h
//  TableViewLibrary
//
//  Created by Krishnan Sriram Rama on 4/24/15.
//  Copyright (c) 2015 Krishnan Sriram Rama. All rights reserved.
//

#import

@interface MyTableViewDetailedWebViewController : UIViewController


@end


//
//  MyTableViewFAQViewController.m
//  TableViewLibrary
//
//  Created by Krishnan Sriram Rama on 4/24/15.
//  Copyright (c) 2015 Krishnan Sriram Rama. All rights reserved.
//

#import "MyTableViewDetailedWebViewController.h"

@interface MyTableViewDetailedWebViewController ()
@property (unsafe_unretained, nonatomic) IBOutlet UIWebView *webview;

@end

@implementation MyTableViewDetailedWebViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.google.com"]];
    [[self webview] loadRequest:request];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

@end

How to use NIB files from library

Create re-usable libraries in iOS


Let's start by creating a simple application
Note: All of my samples are done with ObjC in XCode 6.3

We have 2 parts for this solution.
An application that displays a tableview of data fetched from a library. When you tap on a cell, we get a detailed view in the form of a webview that was added as a bundle to library.

Now that the objective is set, let's ensure we have the application ready to do what we need


  1. Open XCode
  2. File -> New Project. Select "Single View Application". Give the application a suitable name. I named it "MyTableViewApplication"
  3. Make sure you have valid entries for Organization name, identifier. Select language to be "ObjectiveC". I created this application for iPhone. You cna choose any device of your choice
  4. Select a directory location
  5. Here's what you'd see as the structure for your application 
  6. We want a simple tableview, but what the template created was a UIViewController based view. Let's quickly change it to a UITableViewController
  7. Delete existing ViewController.m and ViewController.h
  8. Create a new class derived from UITableViewController say "MyTableViewController". You can as well change the ViewController base class from UIViewController to UITableViewController, if you want.
  9. Open up Main.storyboard. Delete existing ViewController
  10. Drag and drop a UITableViewController. Associate this new Controller to "MyTableViewController"
  11. Select the new TableViewController, go over to AttributesInspector pane and check "Is initial view controller", if it is not already checked.
  12. New folder structure should be like this
  13. When executed, here's what you should see


We now have a basic application, lets go create a re-usable library


  1. File -> New Project, select "Framework and Library" -> "Cocoa Touch Static Library". Give it a name "MySampleLibrary"
  2. Basic project will have nothing more than a class - "MySampleLibrary" in the form of .m and .h
  3. I prefer to reserve this class for generic stuff and I create custom classes for all purposes. To start with lets create a simple class MyTableViewCellData.
  4. Contents of MyTableViewCellData.h and MyTableViewCellData.m
  5. I want to create a collection that will be consumed by my application, hence I created "MyTableViewCellDataCollection".
  6. Contents of MyTableViewCellDataCollection.h" and MyTableViewCellDataCollection.m
  7. In order for the 2 classes to be visible in our application, we have to ensure we make them available along with the libraries header files. We do that by opening up the build phases for the target, expand "copy files" section, tap on the small "+" sign at the bottom and add "MyTableViewCellDataCollection.h" and "MyTableViewCellData.h". 
  8. Compile code. If all is well, We need to copy over our library and header file for our application. To locate them. From Window menu select "Projects", select "MySampleLibrary", tap on the small arrow, displayed right after location of "Derived Data". This will open up finder.
  9. Browse into "MySampleLibrary-XXXX" -> Build -> Products -> Debug-iphonesimulator. You'll see "libMySampleLibrary.a", "include" directory. Copy both of them to a temporary folder or to a more accessible location


Consuming library


  1. Open up "MyTableViewApplication", create a "group" say "CustomExternalLibraries" (I prefer creating physical directories, over groups. For convenience sake, lets create a group), add "libMySampleLibrary.a" and "include" directory. Project structure should be like the following 
  2. Add needed header files into "MyTableViewController"
  3. Code for MyTableViewController.m and MyTableViewController.h
  4. When the code is compiled and executed, here's what you should see


Bundle nib files with in library


  1. Add a new ViewController "MyTableViewDetailedWebViewController" with class and nib file
  2. Add a webview into ViewController. Connect IBOutlet. Code for MyTableViewDetailedWebViewController.h and MyTableViewDetailedWebViewController.m
  3. Select "MySampleLibrary" target, select "Build Phases", Tap "+" and add "MyTableViewDetailedWebViewController" to build phases 
  4. File -> New -> Target, Select "Framework and Library" from OSX, select "Bundle", tap on Next. Give it a name "MySampleLibraryBundle".
  5. Select the bundle target, Add nib file for "MyTableViewDetailedWebViewController" in "Copy Bundle Resources" 
  6. Select bundle target, select "Bundle Settings", Change "Base SDK" from OSX to "ios X.x" 
  7. Select the bundle target, "MySampleLibraryBundle" from schemes above and build.
  8. Switch back to "MySampleLibrary", compile. All should be good
  9. Go into the DerivedData folder of library, like previously, pick up .a file, include directory and .bundle file. Move it to a more accessible directory.


Consuming nib files in main application


  1. Add .a, headers and bundle file
  2. Make changes to didSelect on tablecell, to present the new viewcontroller added in bundle. Updated MyTableViewController code
  3. When executed, user taps on a cell, we show a detailed webview, like the following 



TableViewController with data from Library

//
//  MyTableViewController.h
//  MyTableViewApplication
//
//  Created by Krishnan Sriram Rama on 4/26/15.
//  Copyright (c) 2015 Krishnan Sriram Rama. All rights reserved.
//

#import

@interface MyTableViewController : UITableViewController


@end


//
//  MyTableViewController.m
//  MyTableViewApplication
//
//  Created by Krishnan Sriram Rama on 4/26/15.
//  Copyright (c) 2015 Krishnan Sriram Rama. All rights reserved.
//

#import "MyTableViewController.h"
#import "MyTableViewCellData.h"
#import "MyTableViewCellDataCollection.h"
#import "MyTableViewDetailedWebViewController.h"

@interface MyTableViewController ()
@property (nonatomic, strong) NSDictionary *tableData;
@end

@implementation MyTableViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self setTableData:[[MyTableViewCellDataCollection sharedManager] tableData]];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [[self tableData] count];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 50.0f;
}

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"];
    NSString *currentIndex = [NSString stringWithFormat:@"%ld", ([indexPath row] + 1)];
    MyTableViewCellData *cellData = [[self tableData] objectForKey:currentIndex];

    [[cell textLabel] setText:[cellData cellData]];
    [[cell detailTextLabel] setText:[cellData subCellData]];
    
    return cell;
}

@end

TableViewController With NIB Connection from Library

//
//  MyTableViewController.h
//  MyTableViewApplication
//
//  Created by Krishnan Sriram Rama on 4/26/15.
//  Copyright (c) 2015 Krishnan Sriram Rama. All rights reserved.
//

#import 

@interface MyTableViewController : UITableViewController


@end


//
//  MyTableViewController.m
//  MyTableViewApplication
//
//  Created by Krishnan Sriram Rama on 4/26/15.
//  Copyright (c) 2015 Krishnan Sriram Rama. All rights reserved.
//

#import "MyTableViewController.h"
#import "MyTableViewCellData.h"
#import "MyTableViewCellDataCollection.h"
#import "MyTableViewDetailedWebViewController.h"

@interface MyTableViewController ()
@property (nonatomicstrongNSDictionary *tableData;
@end

@implementation MyTableViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self setTableData:[[MyTableViewCellDataCollection sharedManagertableData]];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [[self tableDatacount];
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 50.0f;
}

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [[UITableViewCell allocinitWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"];
    NSString *currentIndex = [NSString stringWithFormat:@"%ld", ([indexPath row] + 1)];
    MyTableViewCellData *cellData = [[self tableDataobjectForKey:currentIndex];

    [[cell textLabelsetText:[cellData cellData]];
    [[cell detailTextLabelsetText:[cellData subCellData]];
    
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:NO];
    NSBundle* bundle = [NSBundle bundleWithURL:[[NSBundle mainBundle]URLForResource:@"MySampleLibraryBundle"
                                                                      withExtension:@"bundle"]];
    MyTableViewDetailedWebViewController *faqController = [[MyTableViewDetailedWebViewController alloc] initWithNibName:@"MyTableViewDetailedWebViewController"
                                                                                                 bundle:bundle];
    [self presentViewController:faqController animated:YES completion:nil];
    
}

@end

TableView model Collection

//
//  MyTableViewCellDataCollection.h
//  TableViewLibrary
//
//  Created by Krishnan Sriram Rama on 4/24/15.
//  Copyright (c) 2015 Krishnan Sriram Rama. All rights reserved.
//

#import

@interface MyTableViewCellDataCollection : NSObject
+ (instancetype)sharedManager;
@property (nonatomic, strong) NSDictionary *tableData;

@end


//
//  MyTableViewCellDataCollection.m
//  TableViewLibrary
//
//  Created by Krishnan Sriram Rama on 4/24/15.
//  Copyright (c) 2015 Krishnan Sriram Rama. All rights reserved.
//

#import "MyTableViewCellDataCollection.h"
#import "MyTableViewCellData.h"

@interface MyTableViewCellDataCollection ()
@end

@implementation MyTableViewCellDataCollection
+ (instancetype)sharedManager {
    static MyTableViewCellDataCollection *sharedMyManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedMyManager = [[self alloc] init];
    });
    return sharedMyManager;
}

- (id)init {
    if (self = [super init]) {
        _tableData = [self loadSampleData];
    }
    return self;
}

- (NSDictionary*)loadSampleData {
    MyTableViewCellData *cell1 = [[MyTableViewCellData alloc] init];
    [cell1 setCellData:@"Mumbai"];
    [cell1 setSubCellData:@"Economic capital of India"];
    
    MyTableViewCellData *cell2 = [[MyTableViewCellData alloc] init];
    [cell2 setCellData:@"Delhi"];
    [cell2 setSubCellData:@"Political capital of India"];
    
    MyTableViewCellData *cell3 = [[MyTableViewCellData alloc] init];
    [cell3 setCellData:@"Bangalore"];
    [cell3 setSubCellData:@"IT capital of India"];
    
    MyTableViewCellData *cell4 = [[MyTableViewCellData alloc] init];
    [cell4 setCellData:@"Hyderabad"];
    [cell4 setSubCellData:@"Innovation capital of India"];
    
    MyTableViewCellData *cell5 = [[MyTableViewCellData alloc] init];
    [cell5 setCellData:@"Chennai"];
    [cell5 setSubCellData:@"Cultural capital of India"];
    
    NSDictionary *sampleData = @{@"1":cell1, @"2":cell2, @"3":cell3, @"4":cell4, @"5":cell5};
    
    return sampleData;
}

@end

TableViewModel for library

//
//  MyTableViewModel.h
//  TableViewLibrary
//
//  Created by Krishnan Sriram Rama on 4/24/15.
//  Copyright (c) 2015 Krishnan Sriram Rama. All rights reserved.
//

#import

@interface MyTableViewCellData : NSObject
@property (nonatomic, copy) NSString *cellData;
@property (nonatomic, copy) NSString *subCellData;

@end



//
//  MyTableViewModel.m
//  TableViewLibrary
//
//  Created by Krishnan Sriram Rama on 4/24/15.
//  Copyright (c) 2015 Krishnan Sriram Rama. All rights reserved.
//

#import "MyTableViewCellData.h"

@implementation MyTableViewCellData

@end