2010年3月28日 星期日

Acer 58 分鐘快修服務

有人電腦有些問題,買的是 Acer 牌!記得以前 Acer 廣告打很兇,有提供 58分鐘快修服務,當初也有點因為這個點才看上的,還推薦幾位朋友買 Acer 的筆電,現在想起來覺得有被騙的感覺。當時有先上網看看他們的維修站地點,的確在台灣各地都分布都還不錯,但今天仔細去查看,發現這 58 分鐘快修服務根本就跟沒有這項服務差不多了!站在工程師的角度,我能體會他們的規劃,但這絕對不足以當作合理的理由,因為大部分的人都是消費者啊。


參考網站:



兩大反感理由:



  1. 提供 58 分鐘快修服務,只有"直營店"才有提供,可以在 Acer服務中心地點查詢 的網頁下面,有這樣的字樣:授權服務中心不適用 58 分鐘快修服務及 9 to 9 維修,造成不便請見諒!

    • 那全台到底有幾間直營店?我在網頁上找的結果,僅有"台北縣、台北市、桃園縣、台中市、高雄市"才有,其他地方只是"授權服務中心",我第一個點想到是花東地區,那邊的人辛辛苦苦地找到維修店,正想要使用這項服務時,才發現這只有限定地區才有 :P 不就又要多花錢車錢來回取貨



  2. 58 分鐘快修服務,提供時間僅有週一至週五,09:00~12:00 和 13:00~17:00 才收件。

    • 仔細一看,中午 12:00 ~ 13:00 還不收件咧!這會不會太怪了,完完全全地避開一般大眾方便送修的時間,想說上班族趁中午來送件,結果他中午卻不收件?怎麼感覺好想要避開別人使用這個服務似的,我覺得快修最適合的大概是上班族吧,又不像學生可以亂翹課,哈




除此之外,他的問與答感覺好像在打預防針,雖然也沒錯啦,大概是怕碰到一直來鬧的人吧?但整體我覺得他的 58 分鐘快修服務據點不夠多,最重要的送修時間限制應該多多替一般民眾考量,工程師還是可以排班的啊 XD 只要肯付錢,我想就有人肯做事囉,最怕不肯花錢又硬ㄠ工程師的老闆,那才是最最惹人厭的。


相關文章:



2010年3月26日 星期五

iOS 開發教學 - 使用 Google Data APIs 以 Login 為例

Google 有一系列的免費服務,大部分都有提供豐富的 APIs 以便其他開發者善加利用,其清單如下:


然而,雖然知道要使用大多是透過網路連線,回傳如 XML 格式的處理,但要自己親手處理還是有些繁雜,幸運的,這些都已經有人處理好囉!


以下就實作一個簡單使用的範例,稍稍繁雜的地方是設定編譯的環境:


  1. 下載程式碼,此例使用 gdata-objectivec-client-1.9.1.zip ,解壓縮後開啟其目錄下的 Source/GData.xcodeproj

  2. 建立一個新的 Project ,[Xcode]->[NewProject]->[iPhone
    OS]->[Application]->[Window-based Application],以 UseGoogleAPI 為例

  3. 接著將 GData 中的 GData Sources 拖拉到 UseGoogleAPI 下面,不勾選 Copy items into destination group's folder

    • 拖拉 GData Sources

  4. 設定 UseGoogleAPI 的編譯環境:

    • 參考 Compiling the Source Files Directly into a Mac or iPhone Application

    • [Xcode]->[Project]->[Edit Project Settings]->[Build]

      • C Language Dialect: C99 [-std=c99]

      • Other C Flags: -DDEBUG=1

        • 開發時可以用的 debug mode

      • Header Search Paths: /usr/include/libxml2

      • Other Linker Flags: -lxml2

      • Other C Flags: -DGDATA_REQUIRE_SERVICE_INCLUDES=1 -DGDATA_INCLUDE_CONTACTS_SERVICE=1

        • 可以精簡編出來的大小,將沒用到的去除

        • 建議最後才加!因為我嘗試一開始就加了反而有些物件宣告會出現 error ,如 expected specifier-qualifier-list before 'GDataServiceGoogleBlogger' ,但明明我已經加了 GDataServiceGoogleBlogger.h 過了!反而試 GDataServiceGoogleContact 沒出錯,完整 code 片段:

          • #import <UIKit/UIKit.h>
            #import "GDataServiceGoogleBlogger.h"
            //#import "GDataServiceGoogleContact.h"

            @interface UseGoogleAPIAppDelegate : NSObject <UIApplicationDelegate> {
                UIWindow *window;
                GDataServiceGoogleBlogger *service;
            //    GDataServiceGoogleContact *service;
            }
            @property (nonatomic, retain) IBOutlet UIWindow *window;
            @end

  5. 以上設定完後,可以先按 Build 一下,即使還沒寫什麼程式,也可以先編看看是否正確,此測試編譯檔案有 282 個。

開始測試 Google Data APIs:

UseGoogleAPIAppDelegate.h

#import <UIKit/UIKit.h>
#import "GDataBlogger.h"
//#import "GDataServiceGoogleBlogger.h"

@interface UseGoogleAPIAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
    IBOutlet UITextField *username;
    IBOutlet UITextField *password;
    IBOutlet UIButton *button;

    GDataServiceGoogleBlogger *service;
    GDataServiceTicket *ticket;
    BOOL logged;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
- (IBAction)doLoginOrLogout;

@end

UseGoogleAPIAppDelegate.m

#import "UseGoogleAPIAppDelegate.h"

@implementation UseGoogleAPIAppDelegate

@synthesize window;

- (IBAction)doLoginOrLogout {
    username.userInteractionEnabled = NO;
    password.userInteractionEnabled = NO;
    if ( logged ) {    // do logout
        [button setTitle: @"登入" forState:UIControlStateNormal];
        logged = NO;
    } else if( [username.text isEqualToString:@""] || [password.text isEqualToString:@""] ) {
        [button setTitle: @"帳密不可為空, 請重新登入" forState:UIControlStateNormal];
        username.userInteractionEnabled = YES;
        password.userInteractionEnabled = YES;
    } else {            // do login
        [button setTitle: @"登入中..." forState:UIControlStateNormal];
        [service setUserCredentialsWithUsername:username.text password:password.text];
        ticket = [service fetchFeedWithURL:[GDataServiceGoogleBlogger blogFeedURLForUserID:kGDataServiceDefaultUser]
                        feedClass:[GDataFeedBlog class]
                        delegate:self
                        didFinishSelector:@selector(checkLogin:finishedWithFeed:error:)];
    }
}

- (void)checkLogin:(GDataServiceTicket *)ticket
      finishedWithFeed:(GDataFeedBase *)feed
                 error:(NSError *)error {
    if (error == nil) {
        logged = YES;
        [button setTitle: @"登出" forState:UIControlStateNormal];
    } else {
        logged = NO;
        username.userInteractionEnabled = YES;
        password.userInteractionEnabled = YES;
        [button setTitle: @"帳密錯誤, 請重新登入" forState:UIControlStateNormal];
    }
}

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    username.keyboardType = UIKeyboardTypeEmailAddress;
    username.returnKeyType = UIReturnKeyDone;
    password.keyboardType = UIKeyboardTypeEmailAddress;
    password.returnKeyType = UIReturnKeyDone;
  
    service = [[GDataServiceGoogleBlogger alloc] init];
    [service setShouldCacheDatedData:YES];
    [service setServiceShouldFollowNextLinks:YES];
  
    logged = NO;
    // Override point for customization after application launch
    [window makeKeyAndVisible];
}

- (void)dealloc {
    [service release];
    [window release];
    [super dealloc];
}

@end

UseGoogleAPIAppDelegate.xib

google_api_xib_layout

排好後,別忘了幫按鈕接上 doLoginOrLogout 事件,除此之外,也接另一條線跟 button 變數結合,這樣才能透過程式去更改按鈕上的文字,其他部分則是把 UITextField 也接好變數,這樣才能從 UI 上把物件的數值取下來。

起始畫面:

google_api_init

輸入帳密錯誤:

google_api_access_fail

帳密欄位空白:

google_api_password_or_id_empty

正確登入後:

google_api_after_login

最後一提的,其實 Google Data APIs Objective-C Client Library 裡頭有附上豐富的 Example 囉,不過一開始編譯時,我是在 Mac OS X 10.6.2 環境,最後會出現找不到 MacOSX10.4u.sdk ,在此我是直接用 MacOSX10.6.sdk 替代,程式至少還跑的起來囉

$ cd /Developer/SDKs/
$ sudo ln -s MacOSX10.6.sdk MacOSX10.4u.sdk

BloggerSample



2010年3月25日 星期四

iOS 開發教學 - Google Map API 之使用 MapKit framework

在 iPhone 的應用程式中,有許多熱門是使用 Google Map 的服務,透過 mobile device 的行動性,使得科技服務與生活有更密切的結合。在此使用 iPhone SDK 3.0 的 Mapkit framework 實作。

相關資料如下:


建立一個新的 Project ,[Xcode]->[Create a New Xcode Project]->[iPhone
OS]->[Application]->[Window-based Application] 取名為 MyMap 。並且對左邊介面上之目錄列表裡的 Framework ,按他一下並點選右鍵來加入 MapKit Framework

[Framework] -> [Add] -> [Existing Frameworks] ->[MapKit.framework]

MyMapAppDelegate.h

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>

@interface MyMapAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
    MKMapView *myMap;    
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

@end

MyMapAppDelegate.m

#import "MyMapAppDelegate.h"

@implementation MyMapAppDelegate

@synthesize window;

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    CGRect full = CGRectMake(0, 0, 320, 460);
    myMap = [[MKMapView alloc] initWithFrame:full];
    [window addSubview:myMap];
    // Override point for customization after application launch
    [window makeKeyAndVisible];
}

- (void)dealloc {
    [myMap release];
    [window release];
    [super dealloc];
}

@end

成果

GMap

以上是一個精簡的範例,但並不實用,而程式碼的重複使用也不佳,更好的使用方式是在為這個範例增加一個 ViewController:

[Xcode]->[File]->[New File]->[Cocoa Touch Class]->[UIViewController subclass] ,在此稱作 GoogleMapView 好了!別忘了勾選 With XIB for user interface

同時修改原先的程式碼:

MyMapAppDelegate.h

#import <UIKit/UIKit.h>
#import "GoogleMapView.h"

@interface MyMapAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
    GoogleMapView *gMap;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

@end

MyMapAppDelegate.m

#import "MyMapAppDelegate.h"

@implementation MyMapAppDelegate

@synthesize window;

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    gMap = [[GoogleMapView alloc] init];
    [window addSubview:gMap.view];
    // Override point for customization after application launch
    [window makeKeyAndVisible];
}

- (void)dealloc {
    [gMap release];
    [window release];
    [super dealloc];
}

@end

新增的程式碼:

GoogleMapView.h

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>

@interface GoogleMapView : UIViewController {
    IBOutlet MKMapView *myMap;
}

@end

GoogleMapView.m

#import "GoogleMapView.h"

@implementation GoogleMapView

/*
 // The designated initializer.  Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
        // Custom initialization
    }
    return self;
}
*/

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];
    myMap = [[MKMapView alloc] initWithFrame:self.view.bounds];
    [self.view addSubview:myMap];
}

// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return YES;
}

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
  
    // Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

- (void)dealloc {
    [myMap release];
    [super dealloc];
}

@end

點擊 GoogleMapView.xib

接下來要設置當 iPhone 轉 90 度依舊能夠填滿整個螢幕,這部份要在 Interface Builder 調整,在 Library 頁面上,找尋 MKMapView 物件並拖拉到 View 的上(可以透過 Library  下方的搜尋),接著也別忘了要按 ctrl 並點選 File's owner 去跟 MKMapView 物件建立 myMap 連線,最後在 Map View Size 那邊可以去調整 Autosizing,把框框四處都點起來,讓他充滿。

MapViewSize

如果不設定的話,那到時候的結果會是這樣:

GMap2

成果:

GMap3

以上只是簡單的呈現 Google Map ,而弄成一個 UIViewController,是方便以後替它增加一些功能以及提供程式的重複使用性,剩下的有空在補上。



2010年3月24日 星期三

iOS 開發教學 - 程式畫面的流程控制: Navigation & Tab Bar Controllers

此教學參考 CS 193P iPhone Application Development - 7. Navigation & Tab Bar Controllers 。

如果想要豐富一個應用程式時,那很容易需要去控制多個操作畫面。例如我想要此程式有兩個功能,理論上就會有兩個按鈕供你按下,然後從主畫面要切換過去,而處理這個動作的部份,靠的就是 Tab Bar Controller!而對於某一個功能中,可能會有一連串的動作要執行,因此畫面也會切換甚至有階層性的關係,這個部分就常使用到 Navigation Controller!在此以 2 個功能作為 demo ,並且每個功能有 1 或 2 個畫面要切換處理。

建立一個新的 Project ,[Xcode]->[Create a New Xcode Project]->[iPhone OS]->[Application]->[Window-based Application] 取名為 MyApp 。

接著,實作上要 bottom up 去想,假設有兩個功能,分別稱作 A 跟 B 功能,其中 A 有 2 個畫面,稱作 A1 跟 A2,B只有一個畫面,那麼實作上就要先規劃這 3 個 View ,在此先實作此 3 個 View ,分別叫做 A1View、A2View 跟 BView :

[Xcode]->[File]->[New File]->[Cocoa Touch Class]->[UIViewController subclass] 並且勾選 With XIB for user interface ,如此一來就可以使用 Interface Builder 來拖拉元件上去!

依序建立 A1View、A2View 跟 BView 後,首先來規劃 A 這個功能,讓他在上頭呈現一個 Button 按下之後可以切換到 A2 畫面,首先先來寫一下程式對應的部份:

A1View.h

 #import <UIKit/UIKit.h>
@interface A1View : UIViewController {
}
- (IBAction)goToA2View:(id)sender;
@end

A1View.m

#import "A1View.h"
#import "A2View.h"

@implementation A1View

- (IBAction)goToA2View:(id)sender {
    A2View *a2View = [[A2View alloc] init];
    [self.navigationController pushViewController:a2View animated:NO];
    [a2View release];
}
/*
 // The designated initializer.  Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
        // Custom initialization
    }
    return self;
}
*/

/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];
}
*/

/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
  
    // Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

- (void)dealloc {
    [super dealloc];
}

@end

接著請點擊 A1View.xib 藉以呼叫 Interface Builder 出來,並拖拉一個 Button 擺在上頭,並且按住 ctrl 點選剛剛那個 Button ,會出現一條線,把它拉到 A1View.xib 的讓他跟 A1View 的 File's Owner 並選擇剛剛實作的 goToA2View 啦,以此讓 UI 上的物件跟程式事件結合

A1View

接著一樣對 A2View.xib ,但僅需拉一些元件出來,方便辨識是 A2View 即可,在此以一個 Label 印出字而已,在此不印出 A2View.h 和 A2View.m 程式碼,因為完全是預設的程式碼而已,可參考 A1View.h 和 A1View.m ,將上頭著色部分去除,以即將 A1View 更新為 A2View 即可。

A2View

接著,也順便弄一下 BView 吧!單純像 A2View 一樣,只對 BView.xib 去增加一個用來分辨的 View 的元件,如 Slider 等。

最後,則是串起這一連串 View 的 MyAppAppDelegate 啦!

MyAppAppDelegate.h

#import <UIKit/UIKit.h>

@interface MyAppAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
    UINavigationController *navBar;
    UITabBarController *tabBar;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

@end

MyAppAppDelegate.m

#import "MyAppAppDelegate.h"
#import "A1View.h"
#import "BView.h"

@implementation MyAppAppDelegate

@synthesize window;

- (void)applicationDidFinishLaunching:(UIApplication *)application {  
  
    navBar = [[UINavigationController alloc] init];
  
    A1View * a1View = [[A1View alloc] init];
    a1View.title = @"AView";
    [navBar pushViewController: a1View animated:NO];
    [a1View release];
  
    BView *bView = [[BView alloc] init];
  
    UITabBarItem *item = [[UITabBarItem alloc] init];
    item.title = @"BView";
    bView.tabBarItem = item;
    [item release];
  
    tabBar = [[UITabBarController alloc] init];
    tabBar.viewControllers = [NSArray arrayWithObjects: navBar , bView, nil];
    [bView release];
  
    [window addSubview:tabBar.view];
    //[window addSubview:navBar.view];
    // Override point for customization after application launch
    [window makeKeyAndVisible];
}

- (void)dealloc {
    [navBar release];
    [tabBar release];
    [window release];
    [super dealloc];
}

@end

運行的主畫面,預設在 AView ,上頭有 Navigation Controller ,下方有 Tab Bar Controller:

mainView

按下 Go to A2View,左上方有出現按鈕可以 Back 回去:

switchA2View

按下 Tab Bar 切換到 BView:

switchBView

以上是一個簡單的實作例子,用以了解如何控制程式頁面的切換囉!除此之外,在 Navigation 上頭也可以分別加一些左右 Button 而底部的 Tab Bar 也可以美化按鈕,在此就不多討論囉。

2010年3月22日 星期一

iOS 開發教學 - 發訊息到 Facebook 塗鴉牆上!使用 Facebook Connect 架構








How To: Implement Facebook Connect on the iPhone in 5 minutes from Cat Lee on Vimeo.

若想要開發一些 iPhone 小軟體,並將一些訊息發佈到 Facebook 上面,可以先逛逛這些頁面:


剩下的就仿造 Facebook
Connect for iPhone - Facebook Developer Wiki
所提到的設定,先到 facebook's facebook-iphone-sdk at master - GitHub 下載相關程式碼,可在右邊直接按 Download Source 下載。

拖拉 FBConnect 目錄

以下參考 iPhone 開發教學 - 環境設置和第一支程式 Hello World 範例,建立一個簡單的範例後,接著去打開下載回來的檔案,此例為 facebook-facebook-iphone-sdk-5382dcd.zip ,並且解開後找其子目錄 src 中,點選開啟 FBConnect.xcodeproj ,接著將 FBConnect 拖拉到 HelloWorld 上頭,並且使用預設選項不勾選 copy items 囉

default_view

接著,設定 HelloWorld 這個專案,[Xcode]->[Project]->[Edit Project Setting]->[Build]->[Search Path]->[Headers Search Paths] 點選右邊空白,增加你下載的 facebook-iphone-sdk 程式碼的位置,在此使用 /Users/uid/Downloads/facebook-facebook-iphone-sdk-5382dcd/src,弄完接著就可以對 HelloWorld 進行編譯看看,[Xcode]->[Project]->[Build] ,在此只看到一個 warning ,先暫時不管他。

開始正式測試 Facebook 與 iPhone 的結合啦

原樣:

HelloWorldAppDelegate.h

#import <UIKit/UIKit.h>

@interface HelloWorldAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
    IBOutlet UILabel *showLabel;
    IBOutlet UIButton *actionButton;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
- (IBAction)updateLabel;

@end

HelloWorldAppDelegate.m

#import "HelloWorldAppDelegate.h"

@implementation HelloWorldAppDelegate

@synthesize window;

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    // Override point for customization after application launch
    [window makeKeyAndVisible];
}
- (void)awakeFromNib {
    showLabel.text = @"Hello World!";
}
- (IBAction)updateLabel {
    static int count = 0;
    showLabel.text = [NSString stringWithFormat: @"Value: %d" , ++count];
}
- (void)dealloc {
    [window release];
    [super dealloc];
}

@end

更改後:

HelloWorldAppDelegate.h

#import <UIKit/UIKit.h>
#import "FBConnect/FBConnect.h"
#import "FBConnect/FBSession.h"
#define FB_APP_KEY @"YOUR_APP_KEY"
#define FB_SEC_KEY @"YOU_SEC_KEY"


@interface HelloWorldAppDelegate : NSObject <UIApplicationDelegate>  {
    UIWindow *window;
    IBOutlet UILabel *showLabel;
    IBOutlet UIButton *actionButton;
    IBOutlet FBLoginButton *fbButton;
    FBSession *fbSession;
    id<FBRequestDelegate> delegate;
    int status;

}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet FBLoginButton *fbButton;
@property (nonatomic, retain) FBSession *fbSession;
@property(nonatomic,assign) id<FBRequestDelegate> delegate;

- (IBAction)updateLabel;

@end

HelloWorldAppDelegate.m

#import "HelloWorldAppDelegate.h"

@implementation HelloWorldAppDelegate

@synthesize window;
@synthesize fbButton;
@synthesize fbSession;
@synthesize delegate;


- (void)applicationDidFinishLaunching:(UIApplication *)application {
    status = 0 ;
    // Override point for customization after application launch
    [window makeKeyAndVisible];
}
- (void)awakeFromNib {
    showLabel.text = @"Hello World!";
    if ( self.fbSession == nil ) {
        self.fbSession = [FBSession sessionForApplication:FB_APP_KEY secret:FB_SEC_KEY delegate:self ];
    }

}
- (void)session:(FBSession*)session didLogin:(FBUID)uid {
    status = 1;
    NSString* fql = [NSString stringWithFormat:@"select uid,name from user where uid == %lld",self.fbSession.uid];
    NSDictionary* params = [NSDictionary  dictionaryWithObject:fql forKey:@"query"];
    [[FBRequest requestWithDelegate:self] call:@"facebook.fql.query" params:params];
}
- (void)request:(FBRequest*)request didLoad:(id)result {
    if ([request.method isEqualToString:@"facebook.fql.query"]) {
        NSString * username = [ ((NSDictionary*)[(NSArray*)result objectAtIndex:0 ]) objectForKey:@"name"] ;
        showLabel.text = [NSString stringWithFormat:@"Hi, %@" , username ];
    }
}
- (IBAction)updateLabel {
    if ( status == 0 ) {    // do login
        FBLoginDialog* dialog = [[[FBLoginDialog alloc] initWithSession:self.fbSession] autorelease];
        [dialog show];
    }
    else {                    // do post to Wall
        FBStreamDialog* dialog = [[[FBStreamDialog alloc] init] autorelease];
        dialog.delegate = self;
        dialog.userMessagePrompt = @"Example prompt";
        dialog.attachment = @
            "{"
                "\"name\":\"Facebook Connect for iPhone\","
                "\"href\":\"http://developers.facebook.com/connect.php?tab=iphone\","
                "\"caption\":\"Caption\","
                "\"description\":\"Description\","
                "\"media\":[{"
                    "\"type\":\"image\","
                    "\"src\":\"http://img40.yfrog.com/img40/5914/iphoneconnectbtn.jpg\","
                    "\"href\":\"http://developers.facebook.com/connect.php?tab=iphone/\"}],"
                "\"properties\":{"
                    "\"another link\":{"
                        "\"text\":\"Facebook home page\","
                        "\"href\":\"http://www.facebook.com\""
                    "}"
                "}"
            "}";
        // dialog.targetId = @"999999"; // replace this with a friend's UID
        [dialog show];
    }
}

- (void)dealloc {
    [self.fbButton release];
    [self.fbSession release];

    [window release];
    [super dealloc];
}

@end

一開始

init

按下按鈕,進入登入畫面

do_login

登入後,顯示暱稱

show nickname

按下按鈕,進入發佈到塗鴉牆的過程

post to wall

輸入資料中

keyin

在 Facebook 上的顯示

on facebook

程式解說:

透過 status 變數控制,當 status ==0 時按下 button 時,歸類在做 login 的動作,等到登入成功後,則 status 更新為 1 ,當 status == 1 時,按下 button 後,則進入發佈到塗鴉牆的動作。

目前程式有點類似拼湊起來的,編譯上會有 warning:

Class 'HelloWorldAppDelegate' does not implement the 'FBSesionDelegate' protocol
Class 'HelloWorldAppDelegate' does not implement the 'FBRequestDelegate'
protocol
Class 'HelloWorldAppDelegate' does not implement the 'FBDialogDelegate'
protocol

建議可以看看 iPhone FBConnect: Facebook Connect Tutorial 所規劃的程式範例,上頭有作架構上的切割,在此只是純粹測試 Facebook API ,除了全部擠在一起外,還有些函數寫的不謹慎,只是恰好此情況不會出現什麼問題囉!