阵列越界,应用程序越慢越慢 [英] Array out of bounds and slow slow app

查看:77
本文介绍了阵列越界,应用程序越慢越慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以下面是我的控制器代码,在选项卡栏上的每个选项卡上我都有四个.我有两个问题.

So below is my code for my controller, which I have four of one for each tab on the tab bar. I have two issues.

  1. 我的数组越界越好,但是我不能追逐它.我在这里想念什么吗?

  1. I am getting an array out bounds but I can't chase it down. Am I missing something here?

第二次启动我的应用程序时,加载选项卡栏的第一个视图需要5到8秒.加载后,我点击了另一个标签,该标签不会变成蓝色,并且该应用在此处停留了3秒钟,然后终于切换了.我是菜鸟,正在这里挣扎.我认为可以通过在另一个线程或其他线程中获取数据来解决此问题?我确定这个控制器充满了错误.

Second when my app starts up it take 5 - 8 seconds before it loads the first view of the tab bar. Once it loads and I click another tab, the tab doesn't turn blue and the app sits there for 3 seconds then finally switches. I am a noob and am struggling here. I think this issue might be fixed by fetching the data in another thread or something? I am sure this controller is full of bugs.

import "AllMackTableViewController.h"
import "PostDetailViewController.h"
import "MackdabMobileAppDelegate.h"
import <QuartzCore/QuartzCore.h>
import "Post.h"

define FONT_SIZE 14.0f
define CELL_CONTENT_WIDTH 254.0f
define CELL_CONTENT_MARGIN 5.0f



@implementation AllMackTableViewController

@synthesize jsonArray;
@synthesize localJsonArray;
@synthesize postDetailViewController;
@synthesize allPostsTableView;
@synthesize fetchedResultsController, managedObjectContext;



@synthesize minuteTimer;
@synthesize regionsTimer;

pragma mark 
pragma mark View lifecycle


 (void)viewDidLoad {
    [super viewDidLoad];

    self.title = NSLocalizedString(@"Feed", @"You're Matching Posts");

    UIBarButtonItem *refreshButton = [[UIBarButtonItem alloc]
                                      initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh
                                      target:self
                                      action:@selector(refresh)];
    self.navigationItem.rightBarButtonItem = refreshButton;
    allPostsTableView.delegate = self;
    [refreshButton release];

    [self refresh];




    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem;
}

 (void)scrollViewDidScroll:(UIScrollView *) scrollView;
{
    CGFloat scrollHeight = scrollView.contentSize.height;
    CGPoint p = scrollView.contentOffset; 

    //NSLog(@"x = %f, y = %f", p.x, p.y);
}



 (void)viewWillAppear:(BOOL)animated {


    /*
     Set up two timers, one that fires every minute, the other every fifteen minutes.

     1/ The time displayed for each time zone must be updated every minute on the minute.
     2/ Time zone data is cached. Some time zones are based on 15 minute differences from GMT, so update the cache every 15 minutes, on the "quarter".
     */

    NSTimer *timer;
    NSDate *date = [NSDate date];

    /*
     Set up a timer to update the table view every minute on the minute so that it shows the current time.
     */
    NSDate *oneMinuteFromNow = [date dateByAddingTimeInterval:60];

    NSCalendarUnit unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit;
    NSDateComponents *timerDateComponents = [calendar components:unitFlags fromDate:oneMinuteFromNow];
    // Add 1 second to make sure the minute update has passed when the timer fires.
    [timerDateComponents setSecond:1];
    NSDate *minuteTimerDate = [calendar dateFromComponents:timerDateComponents];

    timer = [[NSTimer alloc] initWithFireDate:minuteTimerDate interval:60 target:self selector:@selector(updateTime:) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    self.minuteTimer = timer;   
    [timer release];



}



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 [self.localJsonArray count];

    NSLog(@"Setting numberOfRowsInSection to %i",[self.localJsonArray count]);
    if ( [jsonArray count] < 9 ) {
        return [self.localJsonArray count];
        NSLog(@"Setting numberOfRowsInSection to %i inside of non add one.",[self.localJsonArray count]);

    } else {
        return [self.localJsonArray count] + 1;
    } 


}

 (void)updateTime:(NSTimer *)timer {
    /*
     To display the current time, redisplay the time labels.
     Don't reload the table view's data as this is unnecessarily expensive  it recalculates the number of cells and the height of each item to determine the total height of the view etc.  The external dimensions of the cells haven't changed, just their contents.
     */
    NSArray *visibleCells = self.tableView.visibleCells;
    for (PostTableCustomCellController *cell in visibleCells) {
        [cell redisplay];
    }

    [self updateRegions];
}



(NSString *)dateDiff:(NSString *)origDate {
    NSDateFormatter *df = [[NSDateFormatter alloc] init];
    [df setFormatterBehavior:NSDateFormatterBehavior10_4];
    [df setDateFormat:@"EEE, dd MMM yy HH:mm:ss VVVV"];
    NSDate *convertedDate = [df dateFromString:origDate];
    [df release];
    NSDate *todayDate = [NSDate date];
    double ti = [convertedDate timeIntervalSinceDate:todayDate];
    ti = ti * 1;
    if(ti < 1) {
        return @"never";
    } else      if (ti < 60) {
        return @"less than a minute ago";
    } else if (ti < 3600) {
        int diff = round(ti / 60);
        return [NSString stringWithFormat:@"%d minutes ago", diff];
    } else if (ti < 86400) {
        int diff = round(ti / 60 / 60);
        return[NSString stringWithFormat:@"%d hours ago", diff];
    } else if (ti < 2629743) {
        int diff = round(ti / 60 / 60 / 24);
        return[NSString stringWithFormat:@"%d days ago", diff];
    } else {
        return @"never";
    }   
}


 (void)updateRegions {
    /*
     The following sets the date for the regions, hence also for the time zone wrappers. This has the sideeffect of "faulting" the time zone wrappers (see TimeZoneWrapper's setDate: method), so can be used to relieve memory pressure.
     */
    NSDate *date = [NSDate date];
    for (Post *post in localJsonArray) {
        post.timeRemaining = [self dateDiff:post.deadline];
    }
}




// Customize the appearance of table view cells.
 (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UILabel *distance;
    UIImage *image = [UIImage imageNamed:@"imageA.png"];
    static NSString *CellIdentifier = @"customCell"; // This is identifier given in IB jason set this.

    PostTableCustomCellController *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (indexPath.row != [localJsonArray count] ) {
        if (cell == nil) {

            NSLog(@"Cell created");

            NSArray *nibObjects = [[NSBundle mainBundle] loadNibNamed:@"PostTableCustomCellController" owner:nil options:nil];

            for(id currentObject in nibObjects)
            {
                if([currentObject isKindOfClass:[PostTableCustomCellController class]])
                {
                    cell = (PostTableCustomCellController *)currentObject;  
                }
            }
        }

        Post *post = [localJsonArray objectAtIndex:indexPath.row];

        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
        [formatter setDateFormat:@"yyyy"];

        //Optionally for time zone converstions
        //[formatter setTimeZone:[NSTimeZone timeZoneWithName:@"..."]];

        NSString *stringFromDate = [formatter stringFromDate:post.deadline];

        cell.authorName.text = post.author;
        cell.deadline.text = stringFromDate;
        cell.budget.text = post.budget;
        cell.description.text = post.description;
        [[cell avatar] setImage:[UIImage imageNamed:@"butterfly.jpeg"]];
        [stringFromDate release];

        NSLog([NSString stringWithFormat:@"%@", post.distance]);
        if([@"" isEqualToString: post.distance] || nil == post.distance) {
            cell.distance.text = @"1 mi.";
        }else{
            cell.distance.text = @"25 mi.";
        }

        Post *myPost = [localJsonArray objectAtIndex:[indexPath row]];

        // Might can remove these
        UILabel *locationLabel = (UILabel *) [cell distance];
        UITextView *postTextView = (UITextView *) [cell description];

        //CGSize maximumLabelSize = CGSizeMake(254,88.0f);

        NSString *text;
        CGSize constraint;
        CGSize size;    
        CGFloat height;
        CGFloat realHeight;
        CGSize expectedLabelSize;

        text = myPost.description;

        constraint = CGSizeMake(CELL_CONTENT_WIDTH  (CELL_CONTENT_MARGIN * 2), 88.0f);

        size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];

        height = MAX(size.height, 35.0f);

        realHeight = height + 36.0f  (10); 

        expectedLabelSize = [text sizeWithFont:[UIFont boldSystemFontOfSize:18.0f] constrainedToSize:CGSizeMake(252.0f, CGFLOAT_MAX) lineBreakMode:UILineBreakModeWordWrap];

        CGRect newFrame = postTextView.frame;
        newFrame.size.height = expectedLabelSize.height;
        newFrame.size.width = 252;
        postTextView.frame = newFrame;


        [[cell description] sizeToFit];

        [[cell viewForBackground] sizeToFit];
        [cell setNeedsDisplay];


    }// Ok, all done for filling the normal cells, next we probaply reach the +1 index, which doesn’t contain anything yet

    if ( [jsonArray count] == 9 ) { // Only call this if the array count is 25
        if(indexPath.row == [localJsonArray count] ) { // Here we check if we reached the end of the index, so the +1 row 
            if (cell == nil) {
                cell = [[[PostTableCustomCellController alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
            }
            // Reset previous content of the cell, I have these defined in a UITableCell subclass, change them where needed
            cell.authorName.text = nil;
            cell.deadline.text = nil;
            cell.budget.text = nil;
            cell.description.text = nil;

            // Here we create the ‘Load more’ cell
            UILabel *loadMore =[[UILabel alloc]initWithFrame: CGRectMake(20,0,362,100)];
            loadMore.textColor = [UIColor blackColor];
            loadMore.highlightedTextColor = [UIColor darkGrayColor];
            loadMore.backgroundColor = [UIColor clearColor];
            loadMore.font=[UIFont fontWithName:@"Verdana" size:20];
            loadMore.textAlignment=UITextAlignmentCenter;
            loadMore.font=[UIFont boldSystemFontOfSize:20];
            loadMore.text=@"Load More..";
            [cell addSubview:loadMore];
        }
    }

    return cell;
}

 (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
    if (indexPath.row != [localJsonArray count] ) {
        Post *myPost = [localJsonArray objectAtIndex:[indexPath row]];
        NSString *text = myPost.description;

        CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH  (CELL_CONTENT_MARGIN * 2), 88.0f);

        CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];

        CGFloat height = MAX(size.height, 35.0f);

        return height + (CELL_CONTENT_MARGIN * 2) + 28.0f; 
    }else{
        return 100.0f;
    }

}

(IBAction)nextTwentyFivePlease:(NSString *)thePostID{
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    self.jsonArray = [Post findNextTwentyFiveRemote:thePostID];
    if (self.localJsonArray == nil) {
        self.localJsonArray = [[NSMutableArray alloc]init]; // init the local array if it’s empty
    }
    [self.localJsonArray addObjectsFromArray:self.jsonArray];
    [self.tableView reloadData];
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}


 (IBAction)refresh {
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    self.jsonArray = [Post findAllRemote];
    if (self.localJsonArray == nil) {
        self.localJsonArray = [[NSMutableArray alloc]init]; // init the local array if it’s empty
    }
    [self.localJsonArray addObjectsFromArray:self.jsonArray];


    //self.localJsonArray = [Post findAllRemote];
    [self.tableView reloadData];
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}


pragma mark 
pragma mark Table view delegate

 (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    if ( [jsonArray count] == 9 ) {  // only check for the load more function if we have 25 results in the dynamic array
        if (indexPath.row == [localJsonArray count] ) { // See if we reached the +1 in the results
            Post *tempPost = [jsonArray objectAtIndex:indexPath.row];
            NSLog('What is at tempPost');
            [self nextTwentyFivePlease:tempPost.postID]; // function to load more results
        }
    } else {
        NSInteger row = [indexPath row];
        if (self.postDetailViewController == nil) {
            PostDetailViewController *aPostDetail = [[PostDetailViewController alloc] initWithNibName:@"PostDetailView" bundle:nil];
            self.postDetailViewController = aPostDetail;
            postDetailViewController.post = [localJsonArray objectAtIndex:row];
            [aPostDetail release];
        }
        postDetailViewController.title = [NSString stringWithFormat:@"Details"];

        MackdabMobileAppDelegate *delegate = [[UIApplication sharedApplication] delegate]; 
        [delegate.allMacksNavController pushViewController:postDetailViewController animated:YES];
        [tableView deselectRowAtIndexPath:indexPath animated:YES];
    }
}


pragma mark 
pragma mark Timer set accessor methods

 (void)setMinuteTimer:(NSTimer *)newTimer {

    if (minuteTimer != newTimer) {
        [minuteTimer invalidate];
        minuteTimer = newTimer;
    }
}


 (void)setRegionsTimer:(NSTimer *)newTimer {

    if (regionsTimer != newTimer) {
        [regionsTimer invalidate];
        regionsTimer = newTimer;
    }
}


pragma mark 
pragma mark Memory management

 (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Relinquish ownership any cached data, images, etc that aren't in use.
}

 (void)viewDidUnload {
    // Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
    // For example: self.myOutlet = nil;
}


 (void)dealloc {
    [allPostsTableView release];
    [postDetailViewController release];
    [localJsonArray release]; // may need to remove this
    [super dealloc];
}


@end

推荐答案

在viewDidLoad中调用的刷新方法中,似乎正在进行大量网络访问以下载某些信息.这就可以解释为什么花这么长时间才能显示您的初始标签.

In your refresh method which is called in viewDidLoad, it appears that it is doing a bunch of network access to download some information. That would explain why it is taking so long to show your initial tab.

您将要在后台线程中进行网络访问,以使您的UI不会阻塞.然后,一旦获得结果,就可以从主线程更新UI.像这样:

You'll want to do that network access in a background thread so that your UI doesn't block. Then once you've gotten the results back you can update your UI from the main thread. Something like:

- (IBAction) refresh {
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    [self performSelectorInBackground:@selector(refreshInBackground) withObject:nil];
}

- (void) refreshInBackground {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    self.jsonArray = [Post findAllRemote];
    if (self.localJsonArray == nil) {
        self.localJsonArray = [[NSMutableArray alloc]init]; // init the local array if it’s empty
    }
    [self.localJsonArray addObjectsFromArray:self.jsonArray];

    [self performSelectorOnMainThread:@selector(refreshComplete) withObject:nil waitUntilDone:NO];

}

- (void) refreshComplete {
    [self.tableView reloadData];
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}

正如Rob在下面的评论中指出的那样,您将希望添加某种标志(或信号量)以避免同时触发多个-refresh调用.线程和竞争条件始终是一个棘手的问题,但是我上面的目标只是让您朝着正确的方向前进,以便您可以将后台线程用于网络调用.

As Rob noted in the comment below, you'll want to add some kind of flag (or semaphore) to avoid firing off multiple -refresh calls at the same time. Threading and race conditions are always a tricky bit, but my goal above was just to get you moving in the right direction so that you can use background threads for your network calls.

这篇关于阵列越界,应用程序越慢越慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆