开发者

iOS (iPhone/iPad) SDK - Using a JSON parser with Twitter's user_timeline

Ok, here is my code:

(appname)AppDelegate.h:

    #import <UIKit/UIKit.h>

    @class TwitterViewContoller;

    @interface <appname>AppDelegate : NSObject <UIApplicationDelegate> {
        UIWindow *window;
        UITabBarController *rootController;
        TwitterViewContoller *viewController;
        NSMutableData *responseData;
        NSMutableArray *tweets;
    }

    @property (nonatomic, retain) IBOutlet UIWindow *window;
    @property (nonatomic, retain) IBOutlet UITabBarController *rootController;
    @property (nonatomic, retain) IBOutlet TwitterViewContoller *viewController;
    @property (nonatomic, retain) NSMutableArray *tweets;

    @end

(appname)AppDelegate.m:

    #import "<appname>AppDelegate.h"
    #import "TwitterViewContoller.h"
    #import "SBJson.h"

    @implementation <appname>AppDelegate

    @synthesize window = _window;
    @synthesize rootController;
    @synthesize viewController;
    @synthesize tweets;

    #pragma mark -
    #pragma mark Application lifecycle

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        // Override point for customization after application launch. 
        responseData = [[NSMutableData data] retain];
        tweets = [NSMutableArray array];

        NSURLRequest *request = [NSURLRequest requestWithURL:
                         [NSURL URLWithString:@"http://api.twitter.com/1/statuses/user_timeline.json?screen_name=USER_NAME_ID"]];

        [[NSURLConnection alloc] initWithRequest:request delegate:self];
        //[window addSubview:rootController.view];  
        //[window makeKeyAndVisible];
        return YES;
    }

    #pragma mark NSURLConnection delegate methods
    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
        [responseData setLength:0];
    }

    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
        [responseData appendData:data];
    }

    - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    }

    - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
        [connection release];
        NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
        [responseData release];

        //NSDictionary *results = [responseString JSONValue]; <---This...

        //NSArray *allTweets = [results objectForKey:@"results"]; <--- and this was original code but it caused an exception,

        NSArray *allTweets = [responseString JSONValue]; //<-- So I used this instead.
        NSLog(@"THE ARRAY = %@", allTweets); //<-- THE ARRAY IS SHOWING FINE IN THE OUTPUT LOG
        [viewController setTweets:allTweets];
        [self.window addSubview:rootController.view];
        [self.window makeKeyAndVisible];

    }

    - (void)dealloc {
        [_window release];
        [rootController release];
        [viewController release];
        [super dealloc];
    }

    @end

TwitterViewContoller.h: (yes, I know I spelt it wrong - lol)

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

    @interface TwitterViewContoller : UIViewController {
        IBOutlet UILabel *label;
        NSArray *tweets;
        IBOutlet UITableView *tview;
    }

    @property(nonatomic, retain) IBOutlet UILabel *label;
    @property(nonatomic, retain) NSArray *tweets;

    @end

TwitterViewContoller.m:

    #import "TwitterViewContoller.h"
    #import "Tweet.h"

    @implementation TwitterViewContoller

    @synthesize label;
    @synthesize tweets;

    #pragma mark -
    #pragma mark Table view data source

    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
        // Return the number of sections.
        return 1;
    }


    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        // Return the number of rows in the section.
        return 20;
    }

    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
        return 80;
    }


    // Customize the appearance of table view cells.
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

        static NSString *CellIdentifier = @"Cell";

        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
        }

        // Configure the cell...
        NSLog(@"THE ARRAY = %@", tweets); //<--ARRAY IS NULL <-- <-- <--
        NSDictionary *aTweet = [tweets objectAtIndex:[indexPath row]];


        cell.textLabel.text = [aTweet objectForKey:@"text"];
        cell.textLabel.adjustsFontSizeToFitWidth = YES;
        cell.textLabel.font = [UIFont systemFontOfSize:12];
        cell.textLabel.minimumFontSize = 10;
        cell.textLabel.numberOfLines = 4;
        cell.textLabel.lineBreakMode = UILineBreakMod开发者_JS百科eWordWrap;

        cell.detailTextLabel.text = [aTweet objectForKey:@"screen_name"];

        NSURL *url = [NSURL URLWithString:[aTweet objectForKey:@"profile_image_url"]];
        NSData *data = [NSData dataWithContentsOfURL:url];
        cell.imageView.image = [UIImage imageWithData:data];
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
        return cell;
    }


    #pragma mark -
    #pragma mark Table view delegate

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
        // Navigation logic may go here. Create and push another view controller.
        /*
             <#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:@"<#Nib name#>" bundle:nil];
             // ...
             // Pass the selected object to the new view controller.
             [self.navigationController pushViewController:detailViewController animated:YES];
             [detailViewController release];
        */
    }

    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
        self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
        if (self) {
            // Custom initialization
        }
        return self;
    }

    - (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.
    }

    #pragma mark - View lifecycle

    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view from its nib.
        tweets = [[NSArray alloc]init];
    }

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

    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
        // Return YES for supported orientations
        return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
    }

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

    @end

The problem is that my UITableView is showing up but none of my tweets are. I have noticed that the "tweets" array in TwitterViewContoller (I know I spelt it wrong) is empty (the null problem is fixed) but "allTweets" in my AppDelegate isn't empty. Any ideas?


Test to ensure that in your app delegate, the viewController property is not nil. If you have miswired it in IB (I don't see any instantiation of it in your app delegate), it will silently fail when you call setTweets.

Also, if your view controller is visible and you re-set the tweets property, the table view won't update itself. Instead of synthesizing your tweets property, write your own getter and setter, like so (you could also use KVO for this purpose if you like)

-(NSMutableArray*)tweets {
    return [[tweets retain] autorelease];
}

-(void)setTweets:(NSMutableArray*)newTweets {
    if(newTweets != tweets) {
        [newTweets retain];
        [tweets release];
        tweets = newTweets;

        [tView reloadData];
    }
}

As an aside, you should have -tableView:numberOfRowsInSection: return [tweets count] rather than a fixed number, and it isn't necessary to implement -tableView:heightForRowAtIndexPath: if your rows are all the same height -- you can just set the rowHeight property in IB or in code on the table view.

Update

If your view controller property isn't getting populated, it might be easiest to just load and add it manually in -application:didFinishLaunchingWithOptions -- I think your current approach of delaying the display of any interface until the web request finishes is conceptually problematic. What happens if the network isn't available? Here's some code:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // ... omitting the first few lines

    // let's make sure that we have the tab bar controller, at least
    NSAssert(nil != self.rootViewController, @"tab bar controller not hooked up!");

    self.viewController = [[[TwitterViewContoller alloc] initWithNibName:@"TwitterViewContoller" andBundle:nil] autorelease];
    self.rootViewController.viewControllers = [NSArray arrayWithObject:self.viewController];

    // this is now the Right Way to set the root view for your app, in iOS 4.0 and later
    self.window.rootViewController = self.rootViewController;
    [self.window makeKeyAndVisible];
}

There are a lot of ways that you can confuse yourself when you're starting a new project. I like to customize all of my views to have hideous background colors at first so I always know if they're on screen or not -- using ugly colors helps ensure that I don't forget to change them later.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜