Friday, May 30, 2014

User gem behind proxy on MAC

1. To use gem command on mac behind proxy, set --http-proxy option
gem install --http-proxy http://corporate-proxy:1234 <gem_name>

2. To update gem
sudo gem update --http-proxy http://proxy:8080 --system 

Sunday, May 25, 2014

Create oData service provider with WCF data service with visual studio 2015

The following steps are used to create oData provider with MS WCF data service

Required software:
SQL server 2012~2014
Visual Studio 2015


1. Create Sample NorthWind database in SQL 2012
   1.1 download Northwind  database from the below link and install
http://www.microsoft.com/en-us/download/details.aspx?id=23654

   1.2 open sql server 2012, open file instnwnd.sql, replace following two lines
exec sp_dboption 'Northwind','trunc. log on chkpt.','true'
exec sp_dboption 'Northwind','select into/bulkcopy','true'
 
with the new line  
ALTER DATABASE Northwind SET RECOVERY SIMPLE
 
  1.3 execute the script and verify the northwind database is created.
 
 
2. Create Data model
  2.0 Create ASP.Net web empty project in VS2015
 
  2.1 right click the solution and select Add new Item, select Data, and ADO.Net entity Data model, named it as Northwind.edmx
  2.2 select EF Designer from Database, and choose Northwind database from SQL Server 2012
  2.3 select Entity Framework 6.x
  2.4 select the checkbox of all tables , deselect views and store procedures
 
3. Create WCF data service
  3.1 right click the solution and select manger NuGet package menu
  3.2 Right-click the project and choose Manage NuGet Packages. From the Manage NuGet Packages dialog, make sure Include Prerelease is selected in the top dropdown box. Search for “Microsoft.OData.EntityFrameworkProvider” and install it.
  3.3 Add new item from Web->WCF Data service 5.6.4, name it as Northwind.svc

  3.2 in Northwind.svc.cs, replace the comment /* TODO: put your data source class name here */ to  
System.Data.Services.Providers.EntityFrameworkDataService< NorthwindEntities >
 
 3.3 Add following lines in InitializeService method
            config.SetEntitySetAccessRule("*", EntitySetRights.All);
          
3.4 select Northwind.svc as starting page and F5 to start the app in IE with URL of 
http://localhost:54108/Northwind.svc/Customers('ALFKI')/Orders?$filter=OrderID eq 10643
The port port 54108 may be different  
3.5 For windows8 and iis 8, you also need to enable ".NET Framework 4.5 Advanced Service" from control panel's Turn Windows Features on or off to allow query on .svc
 
4. Create client application
   4.1 create a .net form applicaton
   4.2 select "view" "Other Windows, Data Source" and select service type to add northwind service as NorthwindClient
   4.3 add a datagridview control and a button, when button is clicked, run the below code
                NorthwindEntities context = new NorthwindEntities(new Uri("http://localhost:54108/Northwind.svc/"));
                context.IgnoreMissingProperties = true;
                var customer = context.Customers.ToList();
                dataGridView1.DataSource = customer; 
   4.4 run the app and click the button to show the customer list
   4.5 Add two textbox for user to input new customer name and id
   4.5 Add a button of "New" to create new customer with the following code
           NorthwindEntities context = new NorthwindEntities(new Uri("http://localhost:54108/Northwind.svc/"));

            context.AddToCustomers(new Customer() { CustomerID = txtID.Text.Trim(), CompanyName = txtName.Text.Trim() });
            context.SaveChanges();
   4.6 get a id and name, click new button, the customer should be added into database
   4.7 add a button of update to update the company name with the below code
             string customerId = txtID.Text.Trim();
             NorthwindEntities context = new NorthwindEntities(new Uri("http://localhost:54108/Northwind.svc/")); 
            var customerToChange = (from customer in context.Customers
                                    where customer.CustomerID == customerId
                                    select customer).Single();
          
            customerToChange.CompanyName = txtName.Text.Trim();
            customerToChange.ContactName = txtName.Text.Trim();

            context.UpdateObject(customerToChange);
             context.SaveChanges();
   4.8 add a button to delete a customer
     string customerId = txtID.Text.Trim();             
            NorthwindEntities context = new NorthwindEntities(new Uri("http://localhost:54108/Northwind.svc/")); 
            var customerToChange = (from customer in context.Customers
                                    where customer.CustomerID == customerId
                                    select customer).Single();
          
           
            context.DeleteObject(customerToChange);
             context.SaveChanges();

Monday, May 19, 2014

ios setCookieAcceptPolicy not shared by apps

In apple document for NSHTTPCookieStorage setCookieAcceptPolicy,  it says "The default cookie accept policy is NSHTTPCookieAcceptPolicyAlways. Changing the cookie policy affects all currently running applications using the cookie storage.". 
The test shows that is not the case, changing the cookie policy in one app will not affect other apps running on the same device.

Friday, May 16, 2014

Warning when using NSLog to log a single NSString as NSLog(str)

When using NSLog to log a single NSString parameter, if NSLog(nstringToLog) is used, a compiler warning of "Format string is not a string literal" will show. This warning message is not very clear, and many developer will just ignore it.

However, using NSLog in this way is quite danger, and may cause your app to crash at runtime, as the string parameter to be logged may contain %, which will be parsed as format place holder,  and at runtime, NSLog method will try to cast random memory address to the type specified by %. For example:
NSString* str = @"%i %@ %@";
NSLog(str);  //output is unpredictable and also may cause crash

The properly way of using NSLog to log a single NSString should be:
NSString* str = @"%i %@ %@";
NSLog(@"%@", str)
which will correctly log the string as "%i %@ %@"


MAC fail to empty recycle/gabbage bin

The mac may fail to empty the recycle bin due to locked files in recycle bin. When it fails to empty the item in recycle bin, it will stop the empty operation and open the Finder show the recycle items.
To fix the issue:
Option 1:
1. open terminal window
2. type
chflags -R nouchg
3. drag the item from Finder's recycle bin, usually it is recovery folder at the end of the item 2's command line
4. run the command, and try again to empty recycle bin

Option 2:
right click recycle bin, once the context menu shows, press shift+option and select empty recycle bin menu. It will delete the locked files.

Tuesday, April 22, 2014

How the XIB resource item connect to IBOutlet or IBAction


The below is a typical code when using xib resource from a IBOutlet property, however, notice the strange thing in headerView property, inside the if block, it just loads the nib file, but not assign the value of _headerView, so how the variable is magically assigned when XIB (nib) resource is loaded?

@interface BNRItemsViewController ()
@property (nonatomic, strong) IBOutlet UIView *headerView;
@end

@implementation BNRItemsViewController
- (UIView *)headerView
{
    // If you have not loaded the headerView yet...
    if (!_headerView) {

        // Load HeaderView.xib
        NSArray* arr = [[NSBundle mainBundle] loadNibNamed:@"HeaderView"
                                      owner:self
                                    options:nil];
    }

    return _headerView;
}
@end

The magic happens with the HeaderView.xib's File Owner settings, in headerview.xib, the file owner is set to BNRItemViewController, in addition, the fileOwner's (i.e BNRItemViewController's headerView property is associated to the UIView control in the xib resource. As a result, when loadNibNamed:owner:options is called, after the resource is loaded into memory, it sets the file owner as self (i.e. currrent BNRItemViewController), and then set the headerView IBOutlet property to the UIView resource item. So the property will be automatically assigned to a loaded uiview instance.

you have now seen that a XIB file can be used any time on any class set to its Files' Owner, any object can load a XIB file manually by sending the message loadNibNamed:owner:options: to the application bundle to associate the resouce with its properties.

Note that a UI control in xib file may also need a delegate to handle its event, this is done by control drag the control to file's Owner, so it specifies whatever object works as file's owner will need to handle the uiview's event.

Thursday, April 17, 2014

Define private property, instance variable and method in objective c

In addtion to public property and method,  public, protected, and private instance can also be defined in objective C header files, and the public and protected instance variable can be accessed by object->instanceVariable from other class or its subclass. Within the same class implementation, the private instance can be accessed either using self->privateVariable or privateVariable directly. The recommended way is self->privateVariable to avoid mixing with local variable with the same name.

Private method, property and instance variable that should not be exposed by header file should be defined in implementation .m file. The class extension can be used to define private property and private method. But private instance variable has to be defined different.

The below sample .h and .m file includes the most common usage

Header file
@interface TestObj : NSObject{
//define instance variables in header file
@public
    NSString* publicInstanceVariable;
@protected
    NSString* protectedInstanceVaraible;
@private
    NSString* privateInstanceVarialble;
}

//define public property
@property (readwrite) NSString* publicProp;

//define public methods
-(NSString*) getPublicProp;
-(void)setInstanceVariable:(NSString*)var;
-(void)setPrivatePropMethod:(NSString*)var;
-(NSString*)getInstanceVariable;
-(NSString*)getPrivateProp;
-(NSString*)callPrivateMethod:(NSString*)parm;
@end

Implementation file
#import "TestObj.h"

@interface TestObj()
    //define private property
    @property NSString* privateProp;

    //define private method
    -(NSString*) privateMethod:(NSString*)parm;
@end

//define private instance variable in .m file
@implementation TestObj{
    NSString* privateInstanceVariable;
}

//implement private method
-(NSString*) privateMethod:(NSString*)parm{
    self->privateInstanceVariable = parm;
    return self->privateInstanceVariable;
}

//implement public method
-(NSString*) getPublicProp{
    return self.publicProp;
}

-(void)setInstanceVariable:(NSString*)var{
    self->privateInstanceVariable = var;
}

-(void)setPrivatePropMethod:(NSString*)var{
    self.privateProp = var;
}

-(NSString*)getInstanceVariable{
    return self->privateInstanceVariable;
}

-(NSString*)getPrivateProp{
    return self.privateProp;
}

-(NSString*)callPrivateMethod:(NSString*)parm{
    return[self privateMethod:parm];
}

@end

Note: class extension is a special case of category without a name; that is, no name is specified between
the ( and ) . class extension can extend the class by adding additional private properties. This is not allowed for named categories