Tuesday, January 10, 2012

iOS: Core Data

File > New Project > Empty Application
Select "Core Data" checkbox

".xcdatamodeld" file created in project

select data model file, "Add Entity" at bottom left corner
"Add attributes" using the "+" sign

File > New File > Core Data > NSManagedObject
Select data model, and entity to create the NS managed object
.h and .m created in project

File > New File > UIViewController

AppDelegate.h (add View controller )

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    // Override point for customization after application launch.
    self.window.backgroundColor = [UIColor whiteColor];
    // ADDED
    StartVC *vc = [[StartVC alloc] initWithNibName:@"StartVC" bundle:nil];
    // ADDED
    self.window.rootViewController = vc;
    // ADDED
    [vc release];
    
    [self.window makeKeyAndVisible];
    return YES;
}

VC .m

for adding/inserting data 
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    
    AppDelegate *ad = [[UIApplication sharedApplication] delegate];
    Property *prop = (Property *)[NSEntityDescription insertNewObjectForEntityForName:@"Property" inManagedObjectContext:ad.managedObjectContext];
    prop.name = @"Sengkang";
    prop.seller = @"Beng";
    prop.price = (NSDecimalNumber *)[NSDecimalNumber numberWithInt: 100000];
    prop.address = @"123, Anchorvale #01-01";
    
    NSError *err;
    if(![ad.managedObjectContext save:&err])
        NSLog(@"error %@", [err domain]);
    else
        NSLog(@"Data added");
}

for reading data
// reading
    NSEntityDescription *desc = [NSEntityDescription entityForName:@"Property" inManagedObjectContext:ad.managedObjectContext];
    NSFetchRequest *req = [[NSFetchRequest alloc] init];
    [req setEntity:desc];
    
    NSArray *obj = [ad.managedObjectContext executeFetchRequest:req error:&err];
    
    for(Property *p in obj)
    {
        NSLog(@"-------------");
        NSLog(@"Property name: %@", p.name);
        NSLog(@"Price: %f", p.price.floatValue);
        NSLog(@"Seller: %@", p.seller);
    }




Monday, January 09, 2012

iOS: XML

Download TBXML http://www.tbxml.co.uk

Add "libz.dylib" into project. Project > main directory > Build phases > link Binary with Libraries > "+" > iOS 5.0 - "libz.dylib" > Add

import "TBXML.h"


- (void)viewDidLoad
{
    [super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
    UITextView *tv = [[UITextView alloc] initWithFrame:CGRectMake(5, 50, self.view.frame.size.width-10, 300)];
    [self.view addSubview:tv];
    
    // load xml file
    TBXML *fileRead = [[TBXML alloc] initWithXMLFile:@"properties.xml"];
    // get root element "list"
    TBXMLElement *root = fileRead.rootXMLElement;
    
    NSString *str = [[NSString alloc] init];
    
    if(root)
    {
        NSLog(@"has root");
        
        // get first "property" child element from root element
        TBXMLElement *property = [TBXML childElementNamed:@"property" parentElement:root];
        
        while(property)
        {
            NSString *name = [TBXML textForElement:[TBXML childElementNamed:@"name" parentElement:property]];
            NSLog(@"name: %@", name);
            NSString *price = [TBXML textForElement:[TBXML childElementNamed:@"price" parentElement:property]];
            NSString *propertyID = [TBXML valueOfAttributeNamed:@"id" forElement:property];
            NSLog(@"id: %@", propertyID);
            
            // use current element "property" to fetch the next sibling "property"
            property = [TBXML nextSiblingNamed:@"property" searchFromElement:property];
            
            // append to string
            str = [str stringByAppendingFormat:@"%@: %@, $%@\n", propertyID, name, price];
        }
        // show on textview
        [tv setText:str];
    }
    
}





Sunday, January 08, 2012

iOS: search bar with table view

// assuming table view is done
VC .h

@interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate>
{
    // ADDED
    NSMutableArray *tableData;
    NSArray *array;
    NSMutableArray *searchResults;
    
    IBOutlet UITableView *tableView;
}

@property (nonatomic, retain) NSArray *array;

@end


// assuming table view is done
VC .m
// ADDED: to search
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    NSLog(@"searching: %@", searchText);
    searchText = [searchText lowercaseString];
    // search for text in array
    if(searchText.length > 0)
    {
        [tableData removeAllObjects];// clear all data
        [searchResults removeAllObjects];
        for (NSString *ostr in array)
        {
            //NSLog(@"looping: %@", str);
            NSString *str = [ostr lowercaseString];
            NSRange range = [str rangeOfString:searchText];
            if(range.location != NSNotFound)
            {
                NSLog(@"matched: %@", searchText);
                [searchResults addObject:ostr];
            }
        }
        //[tableData removeAllObjects];
        [tableData addObjectsFromArray:searchResults];
        [tableView reloadData];
    }
    else
    {
        [tableData removeAllObjects];// clear all data
        [tableData addObjectsFromArray:array];
        [tableView reloadData];
    }
}


- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
    NSLog(@"Cancel Button Clicked");
    [searchBar resignFirstResponder]; // close keyboard
}

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
    NSLog(@"Search Button Clicked");
    [searchBar resignFirstResponder]; // close keyboard

}

- (void)viewDidLoad
{
    [super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
    tableView.delegate = self;
    tableView.dataSource = self;
    
    // ADDED
    self.array = [NSArray arrayWithObjects:@"Beng", @"Seng", @"Lian", @"Beng2", @"Seng2", @"Lian2", nil];
    // must alloc and init. strange. cannot use arrayWithArray
    tableData = [[NSMutableArray alloc] init]; //[NSMutableArray arrayWithArray:self.array];
    searchResults = [[NSMutableArray alloc] init];//[NSMutableArray arrayWithArray:self.array];
    [tableData addObjectsFromArray:self.array];
    
    UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width0)];
    [searchBar sizeToFit];
    searchBar.delegate = self;
    [searchBar setShowsCancelButton:YES animated:YES];
    //[searchBar showsSearchResultsButton];
    [self.view addSubview:searchBar];
    
    // place tableview just below search bar. else, the first row of the table view will be hidden behind search bar
    // hence adjust the y and height in the (x,y,w,h) of the table view's frame
    [tableView setFrame:CGRectMake(0, searchBar.frame.size.height, tableView.frame.size.width, tableView.frame.size.height - searchBar.frame.size.height)];
}



Saturday, January 07, 2012

iOS: Table View

// in table view controller .h

@interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
{
    // ADDED
    NSArray *array;
    IBOutlet UITableView *tableView;
}

@property (nonatomic, retain) NSArray *array;

@end

// in table view controller .m
@implementation ViewController
@synthesize array;

// ADDED: method to handle table cell click
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"click cell: %i", indexPath.row);
    // show another VC
    AboutVC *avc = [[AboutVC alloc] initWithNibName:@"AboutVC" bundle:nil];
    [self.view addSubview:avc.view];
}

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *MyIdentifier = @"MyIdentifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] autorelease];
    }
    // ADDED
    cell.textLabel.text = [self.array objectAtIndex:indexPath.row]; // text label of the cell
    cell.imageView.image = [UIImage imageNamed:@"myimage.gif"]; // image on the left
    cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton; // show a '>' button
    // end 
    
    return cell;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
    tableView.delegate = self;
    tableView.dataSource = self;
    
    // ADDED
    self.array = [NSArray arrayWithObjects:@"Beng", @"Seng", @"Lian", nil];
}







iOS: UITabBarController


// in root view controller .m

- (void)viewDidLoad
{
    [super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
    UITabBarController *tbc = [[UITabBarController alloc] init];
    
    // create VC instances
    AboutVC *avc = [[AboutVC alloc] initWithNibName:@"AboutVC" bundle:nil];
    ContactVC *cvc = [[ContactVC alloc] initWithNibName:@"ContactVC" bundle:nil];
    
    // set tab bar properties if necessary. use system defined tab if necessary
    UITabBarItem *tbitem = [[UITabBarItem alloc] initWithTabBarSystemItem:UITabBarSystemItemFavorites tag:1];
    // link VC to this tab bar item
    [cvc setTabBarItem:tbitem];
    
    // interesting that if title is set in VC, it overrides the title here
    UITabBarItem *tbitem2 = [[UITabBarItem alloc] initWithTitle:@"Hmm" image:[UIImage imageNamed:@"myimage.gif"] tag:2];
    // link VC to this tab bar item
    [avc setTabBarItem:tbitem2];
    
    // create array storing all the VCs
    NSArray *arr = [NSArray arrayWithObjects:avc, cvc, nil] ;
    
    // link array to tab bar controller. if title is set in VC, it will show in tab bar
    [tbc setViewControllers:arr];
    
    // set the view bounds of tab bar
    [tbc.view setFrame:self.view.bounds];
    
    // add tab bar to current view
    [self.view addSubview:tbc.view];
}

iOS: UINavigationController


// in app delegate .m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    // Override point for customization after application launch.
    self.viewController = [[[ViewController alloc] initWithNibName:@"ViewController" bundle:nil] autorelease];
    
    //NEW - start
    UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:self.viewController];
    self.window.rootViewController = nc;
    [nc release];
    // end

    [self.window makeKeyAndVisible];
    return YES;
}

// in viewcontroller .m ; assume IBAction to a button to click to go to another VC
-(IBAction) m1:(id)sender
{
    NSLog(@"about us");
    // NEW: create VC instance and push into nav controller
    AboutVC *about = [[AboutVC alloc] initWithNibName:@"AboutVC" bundle:nil];
    [self.navigationController pushViewController:about animated:YES];
}

// in AboutVC.m
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    // NEW: set title on title bar of nav controller
    [self setTitle:@"About Us"];
}

iOS: Delegates

it works like an interface
Example:

@interface myVC:UIViewController <UIWebViewDelegate>
{
}
@end

// assume webViewToLoad IBOutlet
[webViewToLoad setDelegate:self];

// implement methods of delegate
-void webViewDidStartLoad: (UIWebView *) webview
{
  NSLog(@"started loading...");
}

-void webViewDidFinishLoad: (UIWebView *) webview
{
  NSLog(@"finished loading...");
}


iOS: Memory management

retain - increment reference count by 1
release - decrement by 1
retainCount - reference count
autorelease

tool
xcode > product > analyze

iOS: UIWebView

Assuming that IBOutlet urlTxtField and webViewToLoad
NSString *urlToLoad = [NSString stringWithString : @"http://www.google.com"];
[self.webViewToLoad loadRequest : [NSURLRequest requestWithURL : [NSURL URLWithString : urlToLoad]]];
[urlTxtField setText : urlToLoad];

// assume button IBAction
[urlTxtField resignFirstResponder]; //dismiss keyboard
[self.webViewToLoad loadRequest : [NSURLRequest requestWithURL : [NSURL URLWithString : urlTxtField.text]]];

iOS: View Programming


Eg.:
UILabel *label = [[UILabel alloc] init];
CGRect bounds = CGRectMake(10, 20, 300, 200);
[label setText:@"This is a label"]; // put some text, if not, nothing seen on screen
[label setFrame:bounds];
[self.view addSubview:label];

// loading image
UIImage *img = [UIImage imageNamed:@"image.jpg"];    
UIImageView *imgView = [[UIImageView alloc] initWithImage:img];
// add to view with the same steps as above
...
// set color
[self.view setBackgroundColor:[UIColor colorWithRed:0.1 green:0.7 blue:0.3 alpha:1]];
Note:
UIButton has a class method to create a button. [UIButton buttonWithType:UIButtonTypeRoundedRect]

To programmatically add an action to a button, use addTarget:action:forControlEvents: of the UIControl
Example:
[button addTarget:self action:@selector(btnPressed:) forControlEvents:UIControlEventTouchUpInside];
...
-(void) btnPressed:(id) sender
{
   UIButton *btn = (UIButton *) sender;
   if([btn.titleLabel.text isEqual:@"button label"])
   {
      // code to do something
   }
}

// to remove
[self.view removeFromSuperview];

To load and display a ViewController from XIB file

Screen01ViewController.m
Screen02ViewController *next = [[Screen02ViewController alloc] initWithNibName:@"Screen02ViewController" bundle:nil];    
[self.view addSubview:next.view]; // will put the new view on top of this current view
...

Screen02ViewController.m
[self.view removeFromSuperview]; // if you are done with this view and wants to close it

iOS: more basics

Random numbers
random() // gives you 0-(2^31-1)
to generate random number from 0 to 9: random() % 10
3 to 18: random() % ( 18-3 +1) + 3

if need numeric pad for textfield, interface builder > text input trait > num pad

Timer
NSTimer
[NSTimer timerWithTimeInterval:0.5 /* seconds */ invocation: invocation repeats:YES]

NSDate
NSDate *now = [[NSDate alloc] init];
[date2 timeIntervalSinceDate:date1]; returns seconds
[date1 release];

iOS basics

- Variables: int, float, double
- Operators: +, -, *, /, %
- Conditional statements: if-else, switch-case
- Loops: for, while, do-while
- printf() function
- viewDidLoad event


Example:
int i = 1;
float f = 2.3;
printf("This is a string with integer: %d and a floating point number: %f", i, f);
NSLog(@"This is a string with integer: %d and a floating point number: %f", i, f);



Constants:
.h
extern const int MY_NUMBER;
.m
const int MY_NUMBER = 123;



Outlets
in .h
UITextField *tf;
@property (nonatomic, retain) IBOutlet UITextField *tf;

in .m
@synthesize tf;
tf.text = @"Hello textfield";

in .xib
Reload class files, if necessary
File's Owner > Ctrl+Click and drag to textfield in "View" > New reference (outlet)

Actions
in .h
-(IBAction) whatToDoWhenButtonClicked:(id)sender;

in .m
-(IBAction) whatToDoWhenButtonClicked:(id)sender {
// do what ever
tf.text = @"button clicked";
}

in .xib
Reload class files, if necessary
Ctrl+click button in "View" and drag to "File's Owner" > "whatToDoWhenButtonClicked" (Action) TouchUpInside

NSString
NSString *str = [NSString stringWithFormat: @"string %@ with %d and %f", someWords, i, f]
float f = [str floatValue]
int i = [str intValue]



Object-Oriented Programming (OOP)
@interface
@property
@implementation
@synchronise
@end
methods








Creating a custom class, MyClass

  1. MyClass.h
    @interface MyClass : NSObject {
       float myfloat;
       int myint;
    }
    @property float myfloat;
    @property int myint;
    -(void) myMethodWithParameter:(float) param1
    @end
  2. MyClass.m
    #import "MyClass.m"
    @implementation MyClass
    @synthesize myfloat;
    @synthesize myint;
    -(void) myMethodWithParameter:(float) param1
    {
       NSLog(@"this is my method with %f", param1);
    }
    @end

Instantiation of an object and using the object

MyClass *myObject = [MyClass alloc];
[myObject init]; // or [[MyClass alloc] init];
[myObject myMethodWithParameter:4.5];
[myObject release];






NSNumber
NSNumber *fNum = [NSNumber numberWithFloat:12.3];
float f = [fNum floatValue];
NSString *str = [fNum stringValue];
NSNumber reference

NSArray & NSMutableArray
NSArray *names01 = [NSArray arrayWithObjects: @"Beng", @"Siti", @"Dinesh"];
NSMutableArray *names02 = [NSMutableArray arrayWithObjects: @"Beng", @"Siti", @"Dinesh"];
int number = [names01 count];
NSString *firstName = [names01 objectAtIndex:0];
OR for fast enumeration
for(NSString *n in names01)
{
NSLog(@"The name is %@", n);
}