2011年12月4日 星期日

從 Xcode 產生給測試人員使用的 .ipa 檔案

since: 2011/12/04
update: 2011/12/04


前置作業參考:

1.
I touchs: Join iOS Developer Program
2. I touchs: 產生可於實體 iDevice 上運行的 App 之 (一) 取得憑證
3. I touchs: 產生可於實體 iDevice 上運行的 App 之 (二) 註冊設備
4. I touchs: 產生可於實體 iDevice 上運行的 App 之 (三) 新增 App ID
5. I touchs: 產生可於實體 iDevice 上運行的 App 之 (四) 新增 Provisioning Profile


-----------------------------------------------------------------------------------

A. 取得 iDevice 的 UDID
Unique Device Identifier

   1. 開啟 iTunes 並連結你的 iDevice (iPhone, iPod Touch or iPad). 
   2. 先點到所連結裝置的地方.
   3. 在: 摘要 > 序號 的地方, 點一下序號, 會切換成顯示: UDID
   4. 這時後, 只要在 iTunes 的 功能列 > 編輯 > 拷貝 即可 copy 到 UDID

-----------------------------------------------------------------------------------

B. 於 iOS Provisioning Portal, 註冊 Device ID

   Provisioning Portal > Devices > Add Devices 

-----------------------------------------------------------------------------------

C. 於 iOS Provisioning Portal, 設定 Distribution Provisioning Profile
    Provisioning Portal > Provisioning > Distribution > 勾選要供測試的 iDevice
    > 按下 Submit > 下載此 Provisioning Profile 並點二下安裝到 Xcode 裡

-----------------------------------------------------------------------------------

D. Xcode 的操作
   1. Xcode > Product > Archive
   > 允許

   2. 在自動跳出的 Archives 視窗中, 按下右方的 Share...

   3. 確認分享的方式(.ipa) 與 Identity 後, 按下 Next

   說明: Identity下拉式選單內容

   > 允許

   4. 存檔後, 即可看到產生的 .ipa 檔案


-----------------------------------------------------------------------------------

E. iTunes:
   接著將此 .ipa 檔案拖拉到 iTunes 的應用程式裡, 並對 iDevice 執行同步

   說明: 確認有被勾選作同步

   同步完成:

2011年12月1日 星期四

Lala's Program Note 實作記錄: 33. 幫 NoteBook 的 TableView 設定背景圖片


since: 2011/12/01
update: 2011/12/02

A. 修改 NoteBookViewController.h 如下:

//@add
- (void)setBackgroundImage:(UIImage *)image;

---------------------------------------------------------------------------------------------

B. 修改 NoteBookViewController.m 如下:


//@add
- (void)setBackgroundImage:(UIImage *)image {
    //UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,320,480)];

    UIImageView *imageView = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
   
    imageView.backgroundColor = [UIColor colorWithPatternImage:image]; 
   
    //設定圖片的透明度 值為 0.0 ~ 1.0(圖片隱藏~完全不隱藏)
    [imageView setAlpha:0.32];
   
    [self.view addSubview:imageView];
    [self.view sendSubviewToBack:imageView];
    //[self.view insertSubview:imageView atIndex:0];
   
    [self.view setOpaque:NO];
    [self.view setBackgroundColor:[UIColor clearColor]];
    //set contentMode to scale aspect to fit
    imageView.contentMode = UIViewContentModeScaleAspectFit;

    [imageView release];
}


- (void)viewDidLoad
{
    [super viewDidLoad];
   
    //@add
    SEL segmentAction = @selector(segmentAction:);
   
    self.navigationItem.rightBarButtonItem = [self segmentBarItemMakeWithSelector:segmentAction btn1Name:@"Trash" btn2Name:@"Add"];

    //@add setBackgroundImage
    [self setBackgroundImage:[UIImage imageNamed:@"pipi_NoteBook.png"]];
    [self.view setNeedsDisplay];
}

2011年11月30日 星期三

Lala's Program Note 實作記錄: 32. viewWillAppear: method 的相關處理

since: 2011/11/30
update: 2011/12/05

A. 當切回到 Favorite 或 Search Tab 時,  若文章已不存在, 則回到 navigationController
   的上一層, 不然就更新 Favorite 的點選狀態.


   => 修改  ArticleViewController.m 檔案如下:
//@add
- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
   
    NSLog(@"call ArticleViewController's viewWillAppear!");
   
    if (![article valueForKey:@"title"]) {
        NSLog(@"article deleted");
        [self.navigationController popViewControllerAnimated:YES];
    }
    else
    {
        [self toggleFavoriteImage:[[article valueForKey:@"favorite"] boolValue]];
    }
}


------------------------------------------------------------------------------------------


B.
當切回到 Search Tab 時, 清除已不存在的 Search Result.

   => 修改  SearchViewController.m 檔案如下:

//@add
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *MyIdentifier = @"SearchCell";
   
    UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:MyIdentifier];
   
    if (cell == nil)
    {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:MyIdentifier] autorelease];
    }
   
    // customize cell
    NoteArticle *noteArticle = [self.fetchedResultsController objectAtIndexPath:indexPath];
   
    //@add
    if (!noteArticle.title) {
        NSLog(@"SearchViewController's noteArticle removed");
        [self searchBarSearchButtonClicked:self.mySearchBar];
       
        return [[[UITableViewCell alloc] init] autorelease];
    }
    else
    {
        //@update
        NSMutableString *cellTitle = [[[NSMutableString alloc] init] autorelease];
        [cellTitle appendString:noteArticle.title];
        cell.textLabel.text = cellTitle;
        cell.textLabel.textColor = [UIColor brownColor];
       
        //@update
        NSMutableString *cellSubTitle = [[[NSMutableString alloc] init] autorelease];
        [cellSubTitle appendString:noteArticle.subTitle];
        cell.detailTextLabel.text = cellSubTitle;
        cell.detailTextLabel.textColor = [UIColor darkGrayColor];
       
        return cell;
    }
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSManagedObject *article = [self.fetchedResultsController objectAtIndexPath:indexPath];
   
    //@add
    if (![article valueForKey:@"title"]) {
        NSLog(@"==> SearchViewController's noteArticle removed");
    }
    else {          
        ArticleViewController *articleViewController = [[ArticleViewController alloc] init];
        articleViewController.article = article;
       
        //@relationship
        articleViewController.title = [[article valueForKey:@"notebook"] valueForKey:@"name"];
       
        //@add
        articleViewController.managedObjectContext = self.managedObjectContext;
       
        [self.navigationController pushViewController:articleViewController animated:YES]; 
       
        [articleViewController release];
    }
}

//@add
- (void)viewWillAppear:(BOOL)animated
{
    NSLog(@"call SearchViewController's viewWillAppear!");
    [super viewWillAppear:animated];
   
    [myTableView reloadData];
}

Close the app with NSTimer

A. 新增一個專案:
   Xcode > File > New > New Project...
   iOS > Application > Empty Application

   Product Name: CloseApp
   Device Family: iPhone
   checked: Use Automatic Reference Couting

---------------------------------------------------------------------------------------------

B. 修改 AppDelegate.h 如下:
#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>
{
    //@add
    NSNumber *myNumber;
}

//@add
@property (nonatomic, strong) NSNumber *myNumber;

@property (strong, nonatomic) UIWindow *window;

//@add
- (void)setProgress;
- (void)goProgress:(NSTimer *)theTimer;

@end

---------------------------------------------------------------------------------------------

C. 修改 AppDelegate.m 如下:
#import "AppDelegate.h"
@interface AppDelegate()
- (void)terminateWithSuccess;
@end   

@implementation AppDelegate
//@add
@synthesize myNumber = _myNumber;

//@add
-(NSNumber *)myNumber
{
    if (!_myNumber) {
        _myNumber = [[NSNumber alloc] initWithInt:0];
    }
    return _myNumber;
}

//@add
- (void)terminateWithSuccess
{
}

//@add
- (void)setProgress
{
    [NSTimer scheduledTimerWithTimeInterval:1.0f
                                     target:self
                                   selector:@selector(goProgress:)
                                   userInfo:nil
                                    repeats:YES];
}

//@add
- (void)goProgress:(NSTimer *)theTimer {
   
    int myInt = [self.myNumber intValue]+1;
    self.myNumber = [NSNumber numberWithInt:myInt];
    NSLog(@"myNumber = %@", self.myNumber);
   
    if (myInt > 10) {
        [theTimer invalidate];
       
        if ([[UIApplication sharedApplication] respondsToSelector:@selector(terminateWithSuccess)]) {

            NSLog(@"call terminateWithSuccess");

            [[UIApplication sharedApplication] performSelector:@selector(terminateWithSuccess)];

        } else {
            NSLog(@"call exit(0)");
            exit(0);
        }
    }
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
   
    //@add
    [self setProgress];
   
    return YES;
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    /*
     Called when the application is about to terminate.
     Save data if appropriate.
     See also applicationDidEnterBackground:.
     */
    //@add
    NSLog(@"call applicationWillTerminate");
}

---------------------------------------------------------------------------------------------

D. 說明:
   1. terminateWithSuccess 是 Apple 的  non-public API, 提交程式時有可能不會
       通過審核, 不過它會呼叫到 applicationWillTerminate: method.  

   2. 或直接使用 exit(0); 來離開程式, 不過它不會呼叫到 applicationWillTerminate:
        method.
 

2011年11月22日 星期二

Stanford CS193p Fall 2011 Note-05

StoryBoard:

A. create a segue:









B. Five kinds of segues:
   1. Push - It is the kind of segue you use when the two Controllers are inside a
       UINavigationController.
   2. Replace - Replaces the right-hand side of a UISplitViewController (iPad only)
   3. Popover - Puts the view controller on the screen in a popover (iPad only)
   4. Modal - Puts the view controller up in a way that blocks the app until it is
       dismissed
   5. Custom - You can create your own subclasses of UIStoryboardSegue

2011年11月19日 星期六

Stanford CS193p Fall 2011 Note-04

Instance vs. Class Methods

Instance Methods:
1. Starts with a dash:
   - (BOOL)dropBomb:(Bomb *)bomb
                                    at:(CGPoint)position
                               from:(double)altitude;

2. "Normal" Instance Methods

3. Calling syntax:
     [<pointer to instance> method]
     e.g.
     Ship *ship = ...; // instance of a Ship
     destroyed = [ship dropBomb:firecracker
                                                      at:dropPoint
                                               from:300.0];

4. self/super is calling instance
    self means "my implementation"
    super means "my superclass's implementation"

Class Methods:
1. Starts with a plus sign:
   + (id) alloc;
   + (Ship *)motherShip;
   + (NSString *)stringWithFormat:...

2. Creation & Utility Methods

3. Calling syntax:
    [Class method]
    e.g.
    Ship *ship = [Ship motherShip];
    NSString *resultString =
    [NSString stringWithFormat:@"%g", result];
    [[ship class] doSomething];

4. self/super is this class
    self means "this class's class methods"
    super means "this class's superclass's class methods"

-----------------------------------------------------------------------------

Coordinates
1. bounds // @property CGRect bounds;
   a. your view's internal drawing space's origin and size
   b. The bounds property is what you use inside your view's own implementation.
   c. It is up to your implementation as to how to interpret the meaning of
       bounds.origin.
       e.g. View B's bounds = ((0,0),(200,250)) // ((x, y), (width, height))  

2. center // @property CGPoint center;
    the center of your view in your superview's coordinate space
     e.g. View B's center = (300,225) // (x, y)

3. frame // @property CGRect frame;
    a rectangle in your superview's coordinate space which entirely contains your
    view's bounds.size
    e.g. View B's frame = ((140,65),(320,320)) // ((x, y), (width, height))

4. Use frame and center to position the view in the hierarchy
    a. These are used by superviews, never inside your UIView subclass's
        implementation.
    b. You might think frame.size is always equal to bounds.size, but you'd be wrong ...
        Because views can be rotated (and scaled and translated too).

2011年11月18日 星期五

Stanford CS193p Fall 2011 Note-03

strong vs weak

1. strong "keep this in the heap until I don't point to it anymore"
    I won't point to it anymore if I set my pointer to it to nil.
    Or if I myself am removed from the heap because no one strongly points to me!

2. weak "keep this as long as someone else points to it strongly"
    If it gets thrown out of the heap, set my pointer to it to nil automatically
    (if user on iOS 5 only).

3. This is not garbage collection!
     It's way better. It's reference counting done automatically for you.

4. Finding out that you are about to leave the heap
    A special method, dealloc, is called on you when your instance's memory is freed
    from the heap. You will rarely ever have to implement this method. It's  "too late"
    to do much useful here.

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

-----------------------------------------------------------------------------

nil

1. The value of an object pointer that does not point to anything
    id obj = nil;
    NSString *hello = nil;

2. Like "zero" for a primitive type (int, double, etc.)
    Actually, it's not "like" zero: it is zero.

3. All instance variables start out set to zero
     Thus, instance variables that are pointers to objects start out with the value of nil.

4. Can be implicitly tested in an if statement
   if (obj) { } // curly braces will execute if obj points to an object
   // i.e. if (obj != nil) { }

5. Sending messages to nil is (mostly) okay. No code gets executed.
   If the method returns a value, it will return zero.
   int i = [obj methodWhichReturnsAnInt]; // i will be zero if obj is nil

6. Be careful if the method returns a C struct. Return value is undefined.
    CGPoint p = [obj getLocation]; // p will have an undefined value if obj is nil

-----------------------------------------------------------------------------