Tuesday, October 30, 2012

Chinese Blog Site: diandian

Weibo is my favorite twitter. In Chinese it means micro blog. Weibo is very populate in China. I have seen some English tweets there. Today, I noticed one my of followers has moved his blog from Sina blogger to Diandian web site. This caused my interest.

Actually I like Sina blogger very much. It has some nice features. However, the only thing I miss is the CSS and HTML control. I cannot define my CSS classes and HTML scripts there. That's why I prefer Google's Blogger. I have my duplicate Chinese blog at Blogger as well. For sure, it is also for backup purpose.

点点 or dian dian in Chinese means bit by bit. As it says in Diandian's about page, all the complicated contents starts from simple points, then lines, curves, pixels, text and more. Its motto is Let blog start simple"(in Chinese). The overall look of dian dian blog site is very simple and clean. Of course, the most attractive point is the feature of customized CSS and HTML with Javascript.

Based on some articles on TechRice, Diandian is a copy of Tumblr, which is popular web based blog service. I tried to explore Tumbler, but I could not find a reason to switch to this site, even it says that you can customized everything.



Although the following diandian.com home page looks like Trumblr.com, there is difference, blank page on diandian.com. According to diandian's plan, they will have some distinctive features for bloggers.



There are many great web services in China. I don't mean I want to get the best blog web site, but I am interested in one with features I want. In addition to that, the popularity and reliability are also very important. I am going to ask my Weibo follower about it. I really like to move my Sina blog to another simple and powerful blog site in China.

I'll keep my update about Chinese blog if I make any significant changes.

References

Read More...

Sunday, October 21, 2012

Mac OS Security: Gatekeeper (1)

Mac Mountain Lion OS 10.8.2 introduced some new changes in the area of OS security. In this blog I am going to explore the first one: Gatekeeper. It is a very interesting concept. Security concern has been with computer OS since it started. How to protect user data, information, and their privacy has become one of most important issues in personal computers. Even Apple's Mac OS has been very strong in terms of fighting computer virus or malware, with the population of Internet, Apple has realized the potential danger of malware invading Mac OS. Macs still takes very  small market share, comparing to Microsoft Windows. This has been used as an excuse for Mac not having much malware attach. However, Apple is aware the potential attack, and has been keeping very close eyes on the battles of malware against to personal computers.

Based on the information from the past WWDC, there some seminars on Mac security issues. I noticed that Apple has learned lessons in this battle. In this battle, most security focuses have been mainly on defensive side. For example, wildly used anti-virus softwares are always one step behind malware. As a result, Windows treats apps from Internet as potential malware and prompt daunting warning messages to let user to make decision to accept them or not. Apple thinks that this would be a never-win-war.

In Mountain Lion OS, Apple introduced Gatekeeper concept. This is based on a very different concept. In stead of black-kist strategy, Apple implements white-list strategy. This is very analogous to security gate in reality. Security guard will allow any one to enter as long as they have proper id card. Alarm will be on if a faulty or unauthorized id is present. As a part of Gatekeeper strategy, Apple asks all the Mac application developers to apply for Apple developer's id. Apple recomments developers to sign their applications with their ids.

Hence Mountain Lion OS introduced a big change. In order to smooth the transition to this new security practice, the new Mac OS provides three convenient options for Mac users to install apps:

  • Mac App Store 
  • Mac App Store and identified developers
  • Anywhere
With those options, users can temporally loose control on Gatekeeper if they want to install known apps without developer id. You can keep your gate door wide open by allowing Any one, but I think most people will choose the first or second option.


I think this will be a new change in app development. Any developer will require to obtain his/her id if he/she wants to distribute apps through internet.

Read More...

Monday, October 15, 2012

VIM Tips: Multiple Commands

This tip may be too simple and not not the best way to do it. However, it saves my tremendous time. Last week, I was going to bring my Visual Studio solution to my work. This solution contains a lots of projects. I realized that there are some namespaces and copy right issues to be updated. I could use VS to do it. But the VS at work is a new one, without tools like Refactory tool, CodRush Express, Resharper.

I did not like the native Find & Replace in VS. I decided to use VIM to do the job. The challenge I faced was that, first, I had to find all the files contains the strings I would like to replace, and secondly, do the find and replace for each file.

I used TotalCommander tool to do the search. It has built-in find feature and it is very powerful. I can easily get the search result files in one panel. Then I added a tool bar associated with VIM (set parameter %P%N). It is a very cool tool.

Next, I tried to use VIM to do replacement manually. I had too many .cs files. It was just to tedious. Then I searched for a way to do replacement, then save the changes and quit. Can I do three commands in one line? Soon I found a way to do it:

:%s/searchpattern/replacement/g | write | q

In VIM the pipe char is used to link a list of commands. This made my job much quicker. Afterward, I found that this could be done on command line like this:

gvim -c "%s/searchpattern/replacement/g | write | q" test.cs

I think that there must be a better way to run a chained command in a Windows command console: first finding all the files containing expected strings, and next using gvim to do the replacement.

Reference




Read More...

Wednesday, October 03, 2012

VIM Tips

Recently I was working on a project to set up a new server. The new server is a replacement of existing one. One of issues I tried to resolve is to migrate permissions from the existing server to the new server. The problem is that there are too many folders to be checked, 4k folders. I need to find a way to export permissions for each folder to a text file.

Quickly I found a command to get permissions:

cacls.exe folderName

It was very nice to find out this command. Then I use Tree to export folders to text file and edited the text file as a batch file. This is a simple batch file, but a long list of folders.

@cacls folder1 > perm.txt
@cacls folder2 >> perm.txt
...
@cacls folder4000 >> perm.txt

I encountered a problem. Some of path was wrong. I think I may missed some parts of their paths. To find out which one is not valid is a challenge. I need to find a productive way to do that. I knew the following command is a convenient way to detect valid path:

@IF NOT EXIST %folder1 ECHO %folder1

I used VIM to help me to create another batch file based on my above batch file. I used the following VIM replacement command to trim my batch file:

:%s/@cacls //g
:%s/ > perm.txt//g
:%s/ >> perm.txt//g

Those are simple VIM find and replace commands. Now I have a list of paths left:

folder1
folder2
...
folder4000

Then I use find and replace with group command to repeat folders with ECHO command:

:%s/\(.*\)/\1 ECHO \1/g

where \(xxx\) is a group. Finally I insert prefixing IF command at each line the the command:

:%s/^/@IF NOT EXIST /g

where ^ is the beginning of line. With above commands, my new batch file was created.

@IF NOT EXIST folder1 ECHO folder1
@IF NOT EXIST folder2 ECHO folder2
...
@IF NOT EXIST folder4000 ECHO folder4000

Soon I found invalid folders and quickly I fixed my scripts.

Read More...

Friday, September 28, 2012

Open Excel File by Double Click

Recently I had experience a problem at work. I cannot open Excel files by double click them. I tried to open from Excel Open menu and it works fine. I have no problems to open other files such as word or txt files.

I checked my other colleagues and they don't have the issue. One of my friend recommended me to find solution from web by googling. Soon I found a solution. This is something related to Excel registry settings. Since the complexity of Windows registry, it is not recommended to directly edit or change settings there. I found that there is file association from File Explorer. Here is what I did.

First, open File Type from Tools menu, locate the XLS (notice the upper case):



Click Advanced button, the following dialog is displayed.



Select Open in Action list. Click on Edit button:



Make sure to clear Use DDE, then click OK. Apply changes. This will be double click on Excel default behavior back.

Reference


Read More...

Tuesday, September 11, 2012

iOS and New iPhone in Tomorrow's Special Event

Apple has been doing special event to release news about devices and software in past years. I have been kept close look at those events since I got my first iMac in 2007. Tomorrow, September 12, 2012, will be another special event.

A lots of rumors are focused on new iPhone or new hardware devices. What I am actually interested in is the formal release date of iOS 6. I have been waiting XCODE update with iOS 6 support this Fall. I have watched WWDC 2012 videos about iOS 6. I really like the new features in iOS 6, both in Objective-C and new UI components. My next app will use some of those new features.

I'll update this blog after all the news will be released in tomorrow's Apple special event. This will determine how I'll be back working on my apps.

Today, September 12, 2012, Apple made a long list of announcements. iPhone 5 looks gorgeous. The most interesting news for me is the iOS 6 release date. It will be available in one week time, next Wednesday, September 19, 2012, before iPhone 5 release (on September 21, 2012). Not sure when the XCODE update will be available.

I am still watching today's Keynote speech, 1 hour 53 minutes. First time in almost 2 hours. I think my internet has some problems, or the Apple site streaming may have issues. I had several times frozen during AirPlay Mirroring. When I went back to my iMac, I still has similar issue. The reason I suspect internet provider issue is that my QQ app lost connections several times. Anyway, I am going to back to the speech.

Read More...

Sunday, September 09, 2012

Get Caller Class Context and Caller Method Names

In my MyLog class, I prefer to print class name and method name in my log messages. What I did before was to use hard coded strings. This practice makes the maintenance difficult, specially when class or method names are changed.

Later I found two nice Cocoa C-Functions to achieve the same result, without any hard-coded strings. Those functions are great way to get context class and method names. Therefore, I added them to MyClass as convenient macros:


#define CALLER_SELECTOR_NAME NSStringFromSelector(_cmd)
#define CALLER_CONTEXT       NSStringFromClass([self class])

Here are examples to use CALLER_CONEXT to initialize MyLog instance and use CALLER_SELECTOR_NAME to get method name:

// ExampleClass1.m
#import "MyLogger.h"
...
@property (strong, nonatomic) MyLogger* logger;
...
@implementation ExampleClass1
...
@synthesize logger;
- (MyLogger *) logger {
   if (!_logger) {
       _logger = [[MyLogger alloc] initWithContext:CALLER_CONTEXT];
   }
   return _logger;
}
...
- (void) viewWillAppear:(BOOL)animated {
   [super viewWillAppear:animated];

   [self.logger debug:
    ^{
        return [NSString stringWithFormat:@"'%@' is called!",
               CALLER_SELECTOR_NAME];
     }
   ];
...
}
...
@end

Here is the result in the debug console:

2012-09-09 14:23:44.990 TapToCount[5260:c07] [DEBUG] ExampleClass1 - 'viewWillAppear:' is called!

Reference

Read More...

Monday, September 03, 2012

Update: MyLog with Block

I wrote a utility class to log messages in Objective-C long time ago. I updated the class with block early this year, which is similar as delegate in C#. The reason I like to use blocks is that I think, it will improve my app performance.

Here is what I did before, taking info as an example:

- (MyLogger*) info:(NSString*)messageFormat, ...;

A message string is passed to info method by using a list of dynamic string parameters. No matter if I enabled info logging level or not, the message string would be built on call.

By using a block, the string is built within a dynamic block of codes. The bock is actually a pointer to a function. The block of codes may not be executed at all if the logging level is not enabled. Therefore, I think this strategy would improve app performance.

typedef NSString* (^MessageBuildBlock_t)();
...
- (MyLogger*) info:(NSString* (^)(void))msgBuildBlock;

The block is defined as a function returning a string. Then the block is used as a parameter for info method.

Reference

Read More...

Sunday, August 26, 2012

Objective-C: Using Swapping to Mock Method Impelmentaion

Recently I read an interest blog on Unit test in Objective-C. A customized class is defined as method-swizzling helper. With this helper class, two methods in two difference class can be easily swapped at runtime. Therefore, by using this strategy, you can easily mock method calls avoid calling to database or making HTTP requests.

The key points for this helper class is based on Objective-C runtime functions.

class_getClassMethod(...)
method_exchangeImplementations(...)

The first method is used to get a class method as a data type Method. The original and swapped methods can be obtained by this function call. Then the second method is used to make an exchange of method implementation.

The blog has an example of this usage. It looks very easy to make a mock of a method implementation, which is a key practice in unit tests.

Reference


Read More...

Saturday, August 18, 2012

Scrollbar in Mac OS

Since 2007, my interest has been shift to iOS and Mac. One thing interesting UI is scroll bar. Apple has changed the behaviour of scrollbar in iOS. The purpose of this change is to utilize the maximum territory space in a scrollable view. The scrollbar will disappear after the view stays static within seconds. To bring it back, you can user touch gestures to swipe the view. All these are handled by OS. This has been in iOS devices for long time.

Since Lion OS,  Apple introduced the similar support in Mac OS. It is a very interesting design. Here is my understanding. The scrollbars (horizontal and vertical ones) are two UI components. When they are visible, they are UI elements with two main purpose:

  1. They provide visual vision of positions of its content, and
  2. They respond to user interaction, moving or scroll to a position when they are clicked or dragged.
When scrollbars are invisible, not only cannot users see content positions or if content is scrollable, users also have no way to interact with scrollbars. In iOS and Mac native applications, this normally does not present any issue. Users can user touch like swipe to check or move content positions.

However, I had a case recently that invisible scrollbars do cause me some trouble. I use web based RDC to connect to Windows. The RDC window was developed in Java, which is based on Java UI component. It does not support swipe gesture. When I saw a blue window, I had no way to scroll its contents even I knew the Start menu there on the bottom behind the window.


What I found there are two solutions to resolve the issue. The first method method is limit to Mountain Lion OS. Windows in ML are resizable by dragging any boarders. By dragging boarders, the scrollbar will appear for a short period of time. With that period, just quickly touch the scrollbar to make a move.


The second solution is to make scrollbars always visible. This can be set in System Preference | General.



Actually, the scrollbar-always-visible looks really ugly after I am getting used to the new-and-clearn views. However, this solution is the only solution when a window is not sizable.

Read More...

Saturday, August 11, 2012

DataGrid and Object Binding

Last week, one of my good friends asked me some questions about using DataGrid in Windows Form app. I looked at his codes. My first reaction, after I saw his codes, was to recommend him using object or class as data source binding instead of SQL or LINQ binding. I have experience using ASP.Net DataGrid with object binding in my previous work proejcts. I like this strategy very much. By using class as data source, as a developer, I have total control of how data being pumped into DataGrid. The comlicated SQL data structure should be left at SQL server side. The .Net project should forcuse on data and UI.

I quickedly showed him an example. First I added an example class MyData as a data object template. Then I added a DataGrid control on a Windows form. I used data source wizard from the form's DataGrid to set up its object data source to MyData. That was very quick and easy, based on my ASP.Net experience. However, the wizard does not provide a way to let me to tell which method the DataGrid to get data. It seems that DataGrid for Window Form is very different from the one for ASP.Net.

After that meeting, one day, I created an example project and tried to figure it out. Now I got the solution. Basically, in the case of Windows Form application, the data source for DataGrid should a be collection, not an object class. It is very different from the case of ASP.Net DataGrid. Since the data source is a collection, the data binding to DataGrid has to be manually added from DataGrid UI wizard. That's very easy to do: adding column header text and data binding property of DataPropertyName.

Here is the simple Windows Form application. I added a DataGrid to Form1.



DataGrid has a designer wizard. Leave the Data Source as default (none). Click on Add Column... to  define data grid columns. For this demo, add two columns: Name and Age, with column header names as: Column Name, Column Age.




In order to bind data to DataGrid, I need to edit columns from Edit Columns... in DataGrid designer. From there, change DataPropertyName to Name and Age.





With above DataGrid settings, I add a simple class of MyData, which will be used as objects to be displayed on the DataGrid with only two properties: Name and Age. I added another static method to return a collection of MyData objects. Here are my simplified codes:

Public Class MyData
 Private m_name As String
 Private m_age As Integer

 Public Sub New(ByVal nameValue As String, _
     ByVal ageValue As Integer)
   m_name = nameValue
   m_age = ageValue
 End Sub

 Public Property Name() As String
   Get
     Return m_name
   End Get
   Set (ByVal value As String)
     m_name = value
   End Set
 End Property

 Public Property Age() As Integer
   Get
     Return m_age
   End Get
   Set (ByVal value As Integer)
     m_age = value
   End Set
 End Property

 Public Shared Function GetObjects() As List(Of MyData)
  Dim list As List(Of MyData)
  list = New List(Of MyData)
  list.Add(New MyData("John", 12))
  list.Add(New MyData("Mike", 21))
  Return list
 End Function
End Class

In reality, this method (GetObjects) should contain codes to get data from database, or to call data bridge to get mapped data from database.

For the Form, the codes are very simple:

Public Class Form1
...
 Private Sub Button1_Click(ByVal sender As System.Object, _
   ByVal e As System.EventArgs) Handles Button1.Click
   Me.DataGridView1.DataSource = MyData.GetObjects()
 End Sub
...
End Class

The basic concept of this strategy is to make the app as simple as possible: only two element in the Windows Form application:

  • a Form with DataGrid as UI; and 
  • MyData as data source template.

In this way, the focuse can be placed on UI, to provide convenient and nice format for client. The data bridge part, which provides data, can be placed in another class, library, or SQL server.

Here is the result of the application:

Read More...

Friday, August 03, 2012

Finished Watching WWDC2012 Videos

Today I finished watching all available WWDC 2012 videos. There 111 video talk shows. I downloaded them in SD format, which are good enough. To view outlines, I found that I can go to HD area to get PDF files. In this way, I can separate videos from PDF files.

WWDC 2012 shows in iTunes grouped in serials. I started from 400 serial, Developer Tools, with 14 shows. Then 700 serial, Core OS, has 14 shows. 200 serial has 42 shows, which is the largest group. Next is 500, with 24 shows in Graphics , Media and Games. 300 serial is for App services, with 11 shows. The last serial, 600, has 6 shows.

I took some notes in Chinese for the first two serials. I cannot keep taking notes for all of the shows.

Reference


Read More...

Tuesday, July 31, 2012

Blogger Challenge

Recently, I have been puzzled by one challenge: update my blogger with a new view. I have been put image as an indicator of the topic in my blog post for long time. What I would like is to place the icon image off the main column just beside my post title, so that it would be much easy to see the topic for each topic, instead of reading title text. It seems simple task, however, with the limitation of Blogger I just cannot make it happen.

Here are what I tried. Starting from blogger template. I found a place to add a div just right before my post title. The div  has a margin like this style:

....
marin:0 -150%;
....

It does show on the left side of my post title. However, within the div, I could not find a way to change image, the icon for my post.

The icon image is defined in my post. It seems that there is no way to set a reference to a blog post element, such as image's src attribute value. There is a variable in blogger's template, but the values are defined within the template.

I might be possible by using Javascript codes. The difficult point is that how I can define a unique DOM element so that I can retrieve element's attribute value? In addition to that, the Javascript codes have to be trigger on Windows load to update out-fly icon images  from posts.

By the time being, I still could not resolve this puzzle. Any suggestions?

Read More...

Sunday, July 15, 2012

Stackoverflow Flaire is added to my blog

Today I finally fulfill my promise to add SO flair to my blog. I found this promise when I searched my blog for "stackoverflow" to see my previous blog on this web service. I soon found my promise on Feb 18, 2011.

To add this section of HTML codes to my blog template should be easy. However, I spent about half hour to do it. For my record, here is what I did.

First open my blog template and edit it. The place I can add is at almost end of the template:

....
<div id='sidebar-wrapper'>
 <b:section class='sidebar' id='sidebar' preferred='yes'>
   <b:widget id='AdSense1' locked='false' title='' type='AdSense'/>
   ....
 </b:section>
 
 <!-- David Chu added this StackOverflow claire here -->
 <br/>
 <p/>
 <p>David Chu&#39;s programming Q&amp;A at stack<b>overflow</b>:</p>
 <a href='http://stackoverflow.com/users/62776/david-chu-ca'>
   <img alt='SO profile for David.Chu.ca'
   src='http://stackoverflow.com/users/flair/62776.png'
   title='SO profile for David.Chu.ca'
   width='208'/>
 </a>
</div>
....

Now the above section of HTML appears at the end of this blog.

By the way, my SO reached to 4k on July 6, 2012. Actually, I have done almost nothing in the past month. It is the time and effort I invested in the past years, the contribution which programmers recognized, to bring my SO this milestone. My reputation points continues to grow, up to 4054 at the time I am writing this blog.

Read More...

Sunday, July 08, 2012

Animation Views

Navigation and Tab Bar controls provide a way to change views. This kind of change looks like one view being completely replaced with another view, or with animation from one view to another view. Sometimes, you may want to both views visible, with one view in transparent mode on the top of another view. This can be done by using UIView animation methods.

Here are some experience when I tried to use technique.

The basic animation method I use is:

[UIView transitionFromView:fromView
                   toView:toView
                 duration:default_animation_duration
                  options:animationTransiationMode
               completion:completion];

I had one issue with this practice with storyboard (iOS 5.0). The view (toView) being on the top of fromView was positioned with an offset from the top.



The above example shows a gap between the navigation bar and the toView (fromView is on the background). As a result, the bottom bar buttons are not visible because it is out of the screen.

This problem can be easily resolved in storyboard. In the storyboard, select the View Controller first. From the right inspector panel, UNCHECK the property: Resize the view from NIB.



With this fix, the result view is displayed as expected.



Reference

Read More...

Monday, July 02, 2012

Reset SQL Server sa Password

Recently I had a request to reset SQl server sa password. The sa was set up long time ago, but it was not documented. SQL as log in was required to set up administration configurations. This kind of case is very common at work. The following are my notes about this experience.

I soon found a solution to resolve the issue. Basically, you need to restart SQL server in single mode first. Then log in to the server machine by using user with Administrative privilege. The steps are very straight forward, however, I was caught for a while with one mistake. You have to put "-m;" in start up parameter at the beginning with no space afterwards.

The following is the screen snapshot of the property page within SQL server configuration tool. By adding "-m;" right at the beginning line of Startup Parameters, the SQL server will be in single mode in the next start up.



Although I was able to reset sa password by using SQL management studio after  SQL server was restarted, I could not log in to SQL server by sa afterwards. It was interesting that the sa Log was set to blocked. I had to unblock it with single mode on second try.  The following was my snapshot of correct setting. Note: the check box of "Login is blocked out" was set when I reset sa password first time.



Reference


Read More...

Tuesday, June 19, 2012

WWDC 2012 Videos Available Now

Today I got news about WWDC 2012 Videos available from Apple's Development site from Weibo. I will be busy to watch all those training videos. The following is the snapshot of iTunes.



Today I only downloaded the first section: Developer Tools with total 28 tracks (14 videos and 14 PDF  slides). HDs are nice but they take too much space and download bandwidth. I only got SD instead, good enough for my, and much quick and less space.

Reference


Read More...

Saturday, June 09, 2012

iOS 6 coming in WWDC 2012

According to the news from AppleInsider, iOS will be announced at WWDC 2012. This is really a welcome news. I have witnessed the evolution of iOS from it start. iOS was really good change with many improvements. For example, I like the storyboard very much. The storyboard makes the development much easy in terms of overall UI layout and workflow.



I guess there will be many great new changes in iOS 6.0. What I want the most is the generic template. It seems to me that I cannot define a generic protocol with generic in iOS or Objective-C, something like:

@protocol myAbstractInterface : NSObject <T>
- (void) methodA<T1>:(T1*) parameter1;
@end

where myAbstractInterface is a template, T and T1 are a generic data types.

Currently, I have use concrete class types for T and T1. I hope Apple would make this feature available so that it makes true OO design much easier. Apple iOS architecture designers may have their own reason not to implement generics in this way, or they may introduce generics with difference strategies, or more efficient and elegant framework.

I'll keep close eye on the coming WWDC in just about 2 days.

References


Read More...

Thursday, June 07, 2012

Change iOS Navigation App to Tab and Nav App

I have an app with UINavigationController as start view. Later on, I wanted to to change the start view with both navigation bar on the top and a group of tab bars on the bottom. There are many apps like this style, however, there is no template for this type of app in XCODE.

This is a frequently asked question on web for iOS development. There are some information available, but most of them are iOS 4.0 or early with xib based interface. For iOS 5.0+, Apple introduced storyboard. I struggled for a while, but finally I figured it out. The fact is that it much easier in iOS storyboard than the previous IB(Interface builder).  Here is the summary of what did.

Add Tab Bar Controller as Start View


My app was designed with XCODE Navigation template.  In the storyboard, the first view of my app's workflow is a Navigation Controller:



I want to change my app's first view with both navigation on top and tab bars on bottom respectively. The first thing I changed was to add a Tab Bar Controller, which is available from storyboard's library (inspector view on the bottom in XCODE). Just drag and drop the Tab bar controller to my storyboard.  Here is what Tab Bar Controller looks like in the storyboard.



Notice that there are three view items being placed in.  The first one is the root or master view: Tab Bar Controller, and other two are normal View Controllers, each with one Tab Bar Item on the bottom in its view. For the later two view controller items, the image and text can be changed from inspector. In addition to views, there are two segues, relationship segue type, being used to link the master Tab Bar Controller to other tab items.

Now it is time to make changes. First, I need to change the master, Tab Bar Controller, to my app's start point. This can be done by checking inspector's property: Is initial view Controller:



Notice that an arrow is added to the Tab Bar Controller on the left.

Then, control+drag Tab Bar Controller on the bottom of the view (right icon) to an existing Navigation Controller. A pop up menu is displayed.  Choose Relationship segue from the pop up menu. That's it! The app is changed to an app with both navigation and tab bars in the first view.

To change the position of tabs, just drag a tab icon and move it around.

Based on this practice, it is very easy to add more view controllers to the tab bar controller: use the relationship segue to link the tab bar controller and other view controllers. All those can be done by just dragging and dropping.

Add Navigation Controllers


To add navigation controller to the start view, simple drag and drop relationship segues so that the existing or the newly added navigation controllers as the next controller after tab bar controller, before other view controllers



Two controllers in a sequence in this way, as a result, will make the start view showing both navigation bar on the top and tab bars on the bottom.

iOS' storyboard makes the change so easy. I really like the improvement of iOS 5. The following sections are additional information about those controllers and my experience of using them.

iOS Controllers: Tab Bar and Navigation


It is important to know that both Tab Bar Controller and Navigation Controllers are only a view component. They are not View Controllers. In other words, they are part of view or window on iPhone or iPad.

Initially, I tried to create customized class based on tab bar controller with navigation delegate.  However, I could not associate my customized class with view controllers. Soon I realized that my customized class is NOT VIEW CONTROLER. In storyboard, the class for Tab Bar Controller or Navigation Controller is Controller, but not View Controller (for example, UITabBarController and UITableViewController).

Both controllers are visible in view controller class, where they are part of view and they direct view flow. For example, the following codes are some examples in a view controller to access to either Tab Bar Controller or Navigation Controller, as well as navigation item.

NSInteger row = [self.tabBarController selectedIndex];
[self.navigationController popToRootViewControllerAnimated:YES];
self.navigationItem.rightBarButtonItem = self.editButtonItem;
self.navigationItem.leftBarButtonItem = nil;

Access to Tab Bar Controller and Tab Bar Item


If you set view's title with a string, the tab bar item's title will be changed, as same as the view's title. Normally, I prefer the tab bar item's title shorter than view's title since tab bat item has limited space. Here is a tip to set tab bar item's tile with a short string and set the view's title with a long string:

self.navigationItem.title = @"Edit entities";
self.navigationController.tabBarItem.title = @"Edit";

Within the storyboard, a tab bar item has a tag property.  This tag's data type is integer. Many developers use the tag value as an identifier for a tab bar.

One thing I realize is that a tab bar item cannot be set as an outlet in a view controller class. The reason is very simple, the "view" class that the tab bar item resides is a controller but view controller. Therefore, you cannot control-drag a tab bar to a view controller as an outlet.





However, it is possible to define a customized class based on UITabBarController and then control+dragging the tab bar item to the customized class as an outlet.  Here is an example I tried:

// my customized class for UITabBarController
@interface NavigationWithTabBarController : UINavigationController

@property (weak, nonatomic) IBOutlet UITabBarItem *myTabBarItem;

@end

// In my view controller .m class
UITabBarItem* tb = [self.navigationController
 performSelector:@selector(myTabBarItem)];

if (tb.tag == 1) ...

Later, I found out that actually, I don't need to define my customized class at all. The tab bar item is accessible from view controller's navigation controller:

// In my view controller .m class
UITabBarItem* tb = self.navigationController.tabBarItem;

if (tb.tag == 1) ...

Even though, I make this note on this experience. There may be cases where a customized class is needed.

Another tip is about disabling tab bars or making tab bar controller on the bottom invisible. With both tab and navigation bars as start view, the tab bar will  always be displayed along navigation. In some cases, you may want to make tab bars invisible. To do that, just  overwrite the following method in your view controller class like this, making tab bars invisible:

#pragma mark - UINavigationController methods overwrites

- (BOOL) hidesBottomBarWhenPushed {
   return YES;
}

To disable tab bar items, for example, to prevent switching to other tabs while editing table view cells, use the following method:

- (void) setTabBarItemsWhileEditing:(BOOL)editing {
   for (UITabBarItem* tabBarItem in [self.tabBarController.tabBar items]) {
       [tabBarItem setEnabled:!editing];
   }
}

This method is also used to enable them when not in editing mode.

Read More...

Saturday, June 02, 2012

CSS Style and HTML PRE tag

I have been puzzled by my recent posts with source codes. I realized that the horizontal scroll bar does not appear in my source code blocks. The only thing I changed was to change the background color from white to black. I have not figured it out why until today.

The technique I used in my Blogger CSS is to define a class with this attribute:

white-space: nowrap


This should be able to let text in a block (div) auto flow horizontally. Today, I examined my previous posts and recent posts, and find nothing wrong with my updated CSS. My div class have the attribute. After looking at context of my code blocks. I saw that I use pre HTML tag to around my codes. In Safari's inspector, the attribute has been overwritten:

white-space: pre;

That's it! Then I tried to bring my white-space back to nowrap like this:

.nowrap > pre:first-child { ## class nowrap then next first child pre selector
 white-space: nowrap ## no wrap
}

This resolves the issue, however, all the codes are in one line. The line breaks within pre blocks are all ignored. Actually, pre HTML tag means to preserve all the format of text within the block. It seems I cannot resolve the issue with both white-space as nowrap with pre HTML tag.

The solution is to add line break tags <br /> within codes and not using pre HTML tag.

Read More...