IOS Sina Weibo client demo Practices (3) Weibo Homepage

Source: Internet
Author: User

The previous Sina Weibo demo has completed the authentication. Next we will start loading and displaying Weibo-related content. In fact, the main task is to call the Weibo API to load the JSON data, parse the data, and organize the data in tableview.


This blog record the first page-Home Page

The home page shows the current login user and the latest Weibo users of interest, the data request uses the API can be https://api.weibo.com/2/statuses/friends_timeline.json or https://api.weibo.com/2/statuses/home_timeline.json, the two returns are the same, note that the HTTP request method is basically get or post.

The following describes the entire implementation process in detail:

① Data request using GCDTo download data in the background, and then organize the UI display in the main thread after the data is downloaded, so that the Weibo content can be viewed smoothly. Otherwise, when you download data synchronously, the main thread will be blocked during the download process. The user experience is very poor. At the beginning, I did this. The consequence is that the data is very stuck during browsing.

-(Void) getweibodata :( INT) page {dispatch_async (dispatch_get_global_queue (0, 0), ^ {HUD = [[mbprogresshud alloc] init]; HUD. dimbackground = yes; HUD. labeltext = @ "loading data... "; [HUD show: Yes]; [self. view addsubview: HUD]; dispatch_sync (bytes (0, 0), ^ {nsurl * url = [nsurl urlwithstring: [infoforsina metadata: Page]; nsurlrequest * requst = [nsurlrequest requestw Ithurl: url]; nsdata * weibodata = [nsurlconnection sendsynchronousrequest: requst failed: Nil error: Nil]; // use jsonkit to parse data nsstring * weibostring = [[nsstring alloc] initwithdata: weibodata encoding: nsutf8stringencoding]; nsdictionary * weibostatusdictionary = [weibostring objectfromjsonstring]; If ([_ array count]! = 0) {[_ array removeallobjects];} [_ array addobjectsfromarray: [weibostatusdictionary objectforkey: @ "statuses"]; for (nsdictionary * dictionary in _ array) {status * status = [[Status alloc] init]; status = [Status initwithjsondictionary: dictionary]; [_ statusarray addobject: Status] ;}}); dispatch_sync (dispatch_get_main_queue (), ^ {[self. tableview reloaddata]; [HUD removefromsuperview] ;});}

The above content is my data request method. There is a page parameter, which is the parameter for continuing to load Weibo as mentioned below. Calling the API to return Weibo content is based on pages, the default number of Weibo entries on one page is 20. after loading the relevant data and JSON parsing, reloaddata is performed on tableview in the main thread. I set two synchronization threads in an asynchronous thread to ensure reload tableview only after data loading and parsing, and I added a prompt box for mbprogresshud during the loading process, so it is added in the first synchronization thread and can be removed in the second synchronization thread. JSON data parsing is nothing to mention. I use the jsonkit third-party class library. Of course, you can also use the built-in JSON data parsing method, but I think jsonkit is more convenient to use. It is just a method called objectfromjsonstring.

② The data structure of Weibo content is also the model. I have created a status class to process this part of the content, including a method for initializing the value assignment-(status *) initwithjsondictionary :( nsdictionary *) dic.

First, we can know from the parameters returned by the API call. The main response parameters are retweeted_status, which indicates the forwarded Weibo content, that is to say, If weibo is a forwarded microblog, we need to process this parameter, that is, call the method above.

Two of them need to specifically deal with the Weibo source and the Weibo sending time.

1. Weibo Source:

"Source": "<a href =" http://weibo.com "rel =" nofollow "> Sina Weibo </a>"
// Parse Source parameter Processes Weibo information source nsstring * src = [DIC objectforkey: @ "Source"]; nsange r = [SRC rangeofstring: @ "<a href"]; nsange end; // The if (R. location! = Nsnotfound) {nsange start = [SRC rangeofstring: @ "<a href = \" "]; If (start. location! = Nsnotfound) {int L = [SRC length]; nsange fromrang = nsmakerange (start. location + start. length, l-start.length-start.location); End = [SRC rangeofstring: @ "\" "Options: nscaseinsensitivesearch range: fromrang]; If (end. location! = Nsnotfound) {R. location = start. location + start. length; R. length = end. location-R. location; self. sourceurl = [SRC substringwithrange: R];} else {self. sourceurl = @ "" ;}} else {self. sourceurl = @ "";} start = [SRC rangeofstring: @ "\"> "]; end = [SRC rangeofstring: @" </a> "]; If (start. location! = Nsnotfound & End. location! = Nsnotfound) {R. location = start. location + start. length; R. length = end. location-R. location; self. source = [SRC substringwithrange: R];} else {self. source = @ "" ;}} else {self. source = SRC ;}

2. Weibo sending time

 "created_at": "Tue May 31 17:46:55 +0800 2011"

This is the returned JSON data. We only need to display the hour minutes and seconds. The following is a solution:

- (NSString *) getTimeString : (NSString *) string {        NSDateFormatter *inputFormatter = [[NSDateFormatter alloc] init];    [inputFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]];    [inputFormatter setDateFormat:@"EEE MMM dd HH:mm:ss Z yyyy"];    NSDate* inputDate = [inputFormatter dateFromString:string];        NSDateFormatter *outputFormatter = [[NSDateFormatter alloc] init];    [outputFormatter setLocale:[NSLocale currentLocale]];    [outputFormatter setDateFormat:@"HH:mm:ss"];    NSString *str = [outputFormatter stringFromDate:inputDate];    return str;}

③ Display of tableview cell content. There are four issues to consider., I noticed that this Part has a lot of content, so I created a tableviewcell class to process this part of content.

First, we have all played the official Sina Weibo. We can know that the content displayed on the Weibo website includes: avatar, nickname, time, number of forwards, comment, Weibo content, Weibo images, for forwarding, you also need to forward the content. If there are images, the Weibo image mentioned above will not be displayed, and the forwarded image will be displayed, this ensures that there is only one image in the content of a microblog.

Second, when organizing the display of the content, I chose to create it in the form of code. The reason for this is that the content of Weibo is dynamically changing (each microblog is different ), therefore, this process is flexible. However, cell reuse also needs to be solved. If this problem is accidentally handled, the result will be that the cell will overlap the content, that is, a lableview of the previous cell may be solved, or the imageview is repeated in the cell below. I have mentioned this in the previous blog. The main solution code is:

If (cell! = Nil) {[Cell removefromsuperview]; // process reuse}

Third, the cell height issue. Obviously, if each Weibo occupies one cell, the natural height is different. I need to calculate the height of each Weibo to adapt, I have also posted a blog post about dynamic cell height adjustment. The following is the code I processed:

-(Cgfloat) tableview :( uitableview *) tableview heightforrowatindexpath :( nsindexpath *) indexpath {status * status = [[Status alloc] init]; status = [self. statusarray objectatindex: [indexpath row]; // set cgfloat yheight = 70.0; // The height of Weibo content cgsize constraint = cgsizemake (cell_content_width-(cell_content_margin * 2 ), maxfloat); cgsize sizeone = [status. text sizewithfont: [uifont systemfontofsize: font_si Ze] constrainedtosize: constraint linebreakmode: nslinebreakbywordwrapping]; yheight + = (sizeone. height + cell_content_margin); // forwarding status * retwitterstatus = status. retweetedstatus; // If (status. hasretwitter &&! [Retwitterstatus isequal: [nsnull null]) {// nsstring * retwittercontenttext = [nsstring stringwithformat: @ "% @: % @", retwitterstatus. screenname, retwitterstatus. text]; cgsize textsize = cgsizemake (bytes-(Bytes * 2), maxfloat); cgsize sizetwo = [retwittercontenttext sizewithfont: [uifont systemfontofsize: font_size] Bytes: textsize linebreakmode: bytes]; yheight + = (sizetwo. height + cell_content_margin); // then, the image will be displayed if (status. haveretwitterimage) // The forwarded Weibo has an image {yheight + = (120 + cell_content_margin) ;}// no forwarded else {// Weibo has an image if (status. hasimage) {yheight + = (120 + cell_content_margin) ;}} yheight + = 20; [_ heightarray addobject: [nsnumber numberwithfloat: yheight]; return yheight ;}

Here, I set the Image Height to 120. I have previously considered setting the image height based on the actual size of the image, but it is difficult to achieve this because my image is downloaded in The GCD asynchronous thread, because the loading of tableviewcell is the first, and the image download is later, unless you can download the image synchronously in the above function, but this will obviously block the main interface, it will be Kaka.
Fourth, the asynchronous download of images (avatar images and Weibo images) in Weibo content also uses GCD.

__block UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectZero];            __block UIImage *image = [[UIImage alloc] init];                  dispatch_async(dispatch_get_global_queue(0, 0), ^{                image = [self getImageFromURL:status.thumbnailPic];                                dispatch_async(dispatch_get_main_queue(), ^{                                        CGSize imageSize = CGSizeMake(image.size.width, image.size.height);                                        [imageView setFrame:CGRectMake((CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN *2) - imageSize.width)/2, contentLabel.frame.origin.y + contentLabel.frame.size.height + CELL_CONTENT_MARGIN, imageSize.width, imageSize.height)];                    [imageView setImage:image];                    [[self contentView] addSubview:imageView];                });            });

This code is an example of how to process and download images in GCD mode. It should be easy to understand.


④ Pull up to continue loading content. Here we need to solve two problems.

First, when calling this API, Weibo data is returned in the form of pagination. The default number of entries per page is 20, which can be seen in the API request parameters, then we request a page, which is equivalent to obtaining a page. If we want to continue loading data, we can continue loading the second page so that we can continue loading, that is to say, you can change the page parameter by calling the getweibodata method mentioned above.

Second, our intention is to load the current tableview when it is pulled down to the bottom, so we need to know when the tableview slides to the end.

- (void) scrollViewDidScroll:(UIScrollView *)scrollView {    CGPoint contentOffsetPoint = self.tableView.contentOffset;    CGRect frame = self.tableView.frame;    if (contentOffsetPoint.y == self.tableView.contentSize.height - frame.size.height)    {        [self getWeiboData:++_page];    }}

First, we need to know that tableview inherits from scrollveiw, so we can call a proxy method in scrollview-(void) scrollviewdidscroll :( uiscrollview *) scrollview to process the drop-down to the bottom of tableview, it may be a bit confusing to see the above Code. The following is an image to explain.

Tableview. Frame indicates the visible area of the view;

Tableview. contentsize: the size of the content view. the unit of size is points. the default size is cgsizezero; this refers to the content View Size of tableview. Here we want to explain that tableview is always tableview. frame content, but the view of other content is just getting out, just like in the above view.

Tableview. contentoffset: the point at which the origin of the content view is offset from the origin of the scroll view. this parameter represents a point, which is relative to tableview. for contentsize, the coordinates of the contentsize are calculated from the top left point.

I don't know whether to understand this. If it is still not very clear, I will add three nslogs to output these values separately, and then I will be very clear about what I am talking about.

⑤ Pull down and refresh.There are two issues to consider;

First, refresh the view. Generally, you can add a button on the navigation item to refresh the page. However, the more common practice is pull-down refresh. Here I use the new feature uirefreshcontrol of ios6 to process pull-down refresh. The implementation of pull-down refresh is very simple, you can also use a third-party class library of egotableviewpullrefresh.

First, let's take a look at the description in the official documentation.

A uirefreshcontrol object provides a standard control that can be used to initiate the refreshing of a table view's contents. You link a refresh control to

Table through

An associated table View Controller object. The table View Controller handles the work of adding the control to the table's visual appearance and managing

The display

Of that control in response to appropriate user gestures.

The uirefreshcontrol object provides a standard refresh controller that can be used to refresh content in tableview. Refresh the controller and link it to a tableview. You can refresh the response by controlling the appropriate user gesture (drop-down.

In addition to assigning a refresh control to a table View Controller's refreshcontrol property, you must configure the Target and Action of the control itself.

The control does not initiate the refresh operation directly. Instead, it sends the uicontroleventvaluechanged event when a refresh operation shold occur.

You must assign an action

Method to this event and use it to perform whatever actions are needed.

In addition to creating a refreshcontrol controller instance, you must configure the control objectives and actions. The controller itself does not directly process the specific operations for starting refresh. On the contrary, when you perform a drop-down operation, it sends the refresh Operation Event of uicontroleventvaluechanged. You must specify the operation method of this event and use it to perform any required operations.

The uitableviewcontroller object that owns a refresh control is also responsible for setting that control's frame rectangle. Thus, you do not need to manage the size

Or position of a refresh control directly in your view hierarchy.

Uitableviewcontroller automatically refreshes the view display.

It has few attributes and methods and is quite simple to use.

Initializing a refresh control
-Init
Accessing the control attributes
Tintcolor Property
Attributedtitle Property
Managing the refresh status
-Beginrefreshing
-Endrefreshing
Refreshing property bool

Second, I used to clear the microblog data array and call the API to request data for refresh data. However, there is a hidden bug in this process, if the tableview has not been fully loaded, you can refresh the view from the drop-down list. This will crash because all the data is cleared during the refresh. If I reinitialize this variable array, it seems that this problem can be solved. The following code is displayed.

-(Void) addrefreshviewcontroller {self. refreshcontrol = [[uirefreshcontrol alloc] init]; self. refreshcontrol. attributedtitle = [[nsattributedstring alloc] initwithstring: @ "pull-down refresh"]; [self. refreshcontrol addtarget: Self action: @ selector (refreshviewcontroleventvaluechanged) forcontrolevents: uicontroleventvaluechanged];}-(void) refreshviewcontroleventvaluechanged {[self. refreshcontrol beginrefreshing]; self. refreshcontrol. attributedtitle = [[nsattributedstring alloc] initwithstring: @ "refreshing... "]; [self defined mselector: @ selector (loaddata) withobject: Nil afterdelay: 1.0f];}-(void) loaddata {/[_ statusarray removeallobjects]; _ statusarray = [[nsmutablearray alloc] init]; // return to the first page _ page = 1; [self getweibodata: _ page]; If (self. refreshcontrol. refreshing = true) {[self. refreshcontrol endrefreshing]; self. refreshcontrol. attributedtitle = [[nsattributedstring alloc] initwithstring: @ "pull-down refresh"] ;}}

This code level should be clear. The first method is to create a refreshcontrol instance and specify the response method. The second method is to start the refresh view processing, and specify the specific refresh operation. The third method is to reload the Weibo data and refresh the view.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.