iOS - Summary of Zhihu daily


I've been writing Zhihu Daily recently. Today I'd like to summarize the problems I've encountered recently.

  1. Encapsulating network requests with Manager has been recorded in previous blogs, but it will not be used in MVC at the beginning. It has blocked the progress. According to the principle of MVC, the requested data should be in C. here, when refreshing the UI, you must return to the main thread, otherwise there will be data loss.
- (void)test {
    [[Manager sharedManager] NetworkQuestSuccess:^(NetWorkModel* _Nonnull mainViewNowModel) {
            NSLog(@"Request succeeded");
        self.netModel = mainViewNowModel;
        // Return to the main thread to load the UI
        dispatch_async(dispatch_get_main_queue(), ^{
           // UI update code
            [self addUI];
        } error:^(NSError * _Nonnull error) {
            NSLog(@"request was aborted");

Because the requested data is required to update the UI, notification value transfer is used here.

- (void)addUI {
    // The notification value is passed to the View interface
    _homeView = [[HomeView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
    [self.view addSubview:_homeView];
    _dictionary = [NSDictionary dictionaryWithObject:self.netModel forKey:@"ansNetModel"];
    [[NSNotificationCenter defaultCenter]postNotificationName:@"firstSender" object:nil userInfo:_dictionary];
  1. Here are some problems of infinite rotation graph
    Here I use the n+2 method, that is, if you need to rotate five pictures, load seven pictures on the scroll view, in which the first one shows the last picture and the last one is the first one. When we draw the last picture, we can immediately jump to the real first one, so as to achieve the effect of infinite rotation visually. Similarly, when drawing to the first picture, ask him to jump to the fifth picture immediately.
    At the same time, when dragging manually, the page is controlled according to the offset.
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
    int page = scrollView.contentOffset.x / WIDTH;
    if (page == 0) {
        _testPageControl.currentPage = page;
        // Change offset to last picture
        scrollView.contentOffset = CGPointMake(WIDTH * 5, 0);
        _testPageControl.currentPage = 4;
    } else if (page == 6) {
        // Change the offset to the first picture
        scrollView.contentOffset = CGPointMake(WIDTH, 0);
        _testPageControl.currentPage = 0;
    } else {
        _testPageControl.currentPage = page - 1;
    // Restart timer
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(runTimer) object:nil];
    [self performSelector:@selector(runTimer) withObject:nil afterDelay:0.4];

- (void) changeImage {
    if (self.currentImageIndex == 5) {
        _testPageControl.currentPage = 0;
    } else {
        _testPageControl.currentPage = self.currentImageIndex;
    CGFloat x = WIDTH * self.currentImageIndex + WIDTH;
    [_topScollView setContentOffset:CGPointMake(x, 0) animated:YES];
    if (self.currentImageIndex == 6) {
        self.currentImageIndex = 0;
        [_topScollView setContentOffset:CGPointMake(WIDTH, 0) animated:NO];
        _testPageControl.currentPage = 0;


When sliding to the left here, the timer is a little broken. Follow up...

  1. After processing the infinite carousel map, you will arrive at the tableView processing the loaded content, as shown below:

    This involves the refresh of the pull-up tableView. To refresh the tableView, you can judge whether the data needs to be refreshed according to the height:
    When the tableview scrolls to the bottom, the mobile phone screen height + contentoffset.y=contentSize.height. Then, when you drag the tableview up to the orange area, contentoffset.y continues to increase, resulting in the mobile phone screen height + contentoffset.y > contentsize.height.
    At this time, it has been explained that the tableView is loaded to the bottom, and the data should be requested at this time. Written in the protocol function, here I call the scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset method, mainly to load the following chrysanthemums.
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
    NSLog(@"did end drag");
    if (self.tableView.contentOffset.y + HEIGHT> self.tableView.contentSize.height) {
        [self.activityIndicator startAnimating];
        [[Manager sharedManager] questBeforeData:^(NetWorkModel* _Nonnull mainViewNowModel)  {
                NSLog(@"Request succeeded");
            for (int i = 0; i < 6; i++) {
                [self->_myDateArray addObject:mainViewNowModel.stories[i]];
                StoriesModel* story = mainViewNowModel.stories[i];
                [self->_downUrlArray addObject:story.url];
            NSLog(@"%@", self->_downUrlArray);
            // Return to the main thread to load the UI
            dispatch_async(dispatch_get_main_queue(), ^{
               // UI update code
                [self reloadTableView];
            } error:^(NSError * _Nonnull error) {
                NSLog(@"request was aborted");
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return _myDateArray.count + 1;

Add the requested data to the array and reload the tableView.
You can complete the pull-up loading:

4. Pull up the refreshed chrysanthemum.
Here you can use the small chrysanthemum provided by iOS. You only need to define the attribute, set the position, and the time of disappearance.

// Set Chrysanthemum
@property (nonatomic, strong) UIActivityIndicatorView * activityIndicator;
- (void)loadflower {
    _activityIndicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:(UIActivityIndicatorViewStyleMedium)];
    //Set the frame of Chrysanthemum
    _activityIndicator.frame= CGRectMake(0.4 * WIDTH, 0.9 * HEIGHT, 100, 100);
    //Set chrysanthemum color
    _activityIndicator.color = [UIColor redColor];
    //Set background color
    _activityIndicator.backgroundColor = [UIColor clearColor];
    //When you first enter this interface, the control will be displayed, and when you stop rotating, it will also be displayed, but it is not rotating. When it is not set or set to YES, the page will not be displayed
    _activityIndicator.hidesWhenStopped = YES;
    [self addSubview:self.activityIndicator];
  1. Extract only numbers from NSString.
NSDate *lastDay = [NSDate dateWithTimeInterval:-24 * a * 60 * 60 sinceDate:date];//The day before
        NSString* dateString = [lastDay description];
        NSString* string = [[NSMutableString alloc] init];
        string = [dateString substringWithRange:NSMakeRange(0, 10)];
        NSCharacterSet *nonDigitCharacterSet = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
        //String after extracting number
        string = [[string componentsSeparatedByCharactersInSet:nonDigitCharacterSet] componentsJoinedByString:@""];
  1. When the data is pulled up and refreshed, the data will be loaded. At first, the NSDate is directly obtained and the time is added according to the minus days. As a result, there will be a problem of time confusion. Finally, an array of storage time is directly opened to judge the time according to the rows of tableView.
// Time to load pull-up data
        if (indexPath.row != 1 && (indexPath.row - 1) % 6 == 0) {
            cell.dateLabel.hidden = NO;
            cell.dateLabel.text = _dateArray[(indexPath.row - 1) / 6 - 1];
  1. The picture loading in Zhihu daily uses the third-party library SDWebImage, which only needs to import the header file
#import "UIImageView+WebCache.h"

Then you can get the picture according to the picture address

 _topImage = [[UIImageView alloc] init];
 _imageString = [_netModel.top_stories[k] valueForKey:@"image"];
 NSLog(@"%@", [_netModel.top_stories[k] image]);
 NSURL* url = [NSURL URLWithString:_imageString];
 [_topImage sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:@"default"]]
  1. Cell click event. When you click cell, you will enter the detailed web page, as shown below:

    WKwebView is used here. I just learned a little about it and know its simple usage: after clicking cell, the web page address is passed into c, and the WebView is received and loaded in c.
- (void)receiveWebView:(NSNotification*)sender {
    _webView = [[WKWebView alloc] initWithFrame:[UIScreen mainScreen].bounds];
    NSURL *url = [NSURL URLWithString:sender.userInfo[@"webString"]];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [_webView loadRequest:request];
    [self loadScrollView];

Tags: iOS

Posted on Sun, 31 Oct 2021 15:28:33 -0400 by crochk