我的 UIActivityIndicatorView 消失得太快,使其无用,延迟是解决此问题的最佳方法吗?
Posted
技术标签:
【中文标题】我的 UIActivityIndicatorView 消失得太快,使其无用,延迟是解决此问题的最佳方法吗?【英文标题】:My UIActivityIndicatorView disappears too soon making it useless, would delay be the best way to fix this? 【发布时间】:2014-02-27 01:06:06 【问题描述】:需要一个加载器和微调器来显示在我的页面上,以显示我的 parse.com 数据库中的人员列表。现在我专注于 UITableViewController 的一个控制器。
这是我的代码:
- (void)viewDidLoad
[super viewDidLoad];
dispatch_queue_t downloadQueue = dispatch_queue_create("downloader", NULL);
UIView *taggedView = [[LoadingView alloc] initWithFrame:[[self view] bounds]];
[taggedView setTag:17];
[[self view] addSubview:taggedView];
dispatch_async(downloadQueue, ^
//Load my data from parse.com here into an NSMutableArray
//which is the used in my datasource methods
NSLog(@"downloading");
dispatch_async(dispatch_get_main_queue(), ^
//Here is where I hide the loader view
NSLog(@"downloading done.");
UIView *viewToRemove = [[self view] viewWithTag:17];
[viewToRemove removeFromSuperview];
);
);
我已经删除了从 parse.com 加载我的数据的代码,以使事情变得更干净,但 commeting 清楚地表明了它的去向。
除非我注释掉 viewToRemove 行,否则我永远不会看到加载程序。然后它显然停留在屏幕上。问题是它只是加载并且被带走太快。同样出于某种原因,我还可以看到表格行线,但我不想看到它们。我希望加载器视图视图覆盖整个区域,直到加载数据,然后可能一两秒后自行删除。
LoaderView 文件(在网上找到):
#import "LoadingView.h"
@implementation LoadingView
#define LABEL_WIDTH 80
#define LABEL_HEIGHT 20
- (id)initWithFrame:(CGRect)frame
self = [super initWithFrame:frame];
if (self)
[self setBackgroundColor:[UIColor whiteColor]];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake((self.bounds.size.width-LABEL_WIDTH)/2+20,
(self.bounds.size.height-LABEL_HEIGHT)/2,
LABEL_WIDTH,
LABEL_HEIGHT)];
label.text = @"Loading…";
label.center = self.center;
UIActivityIndicatorView* spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
spinner.frame = CGRectMake(label.frame.origin.x - LABEL_HEIGHT - 5,
label.frame.origin.y,
LABEL_HEIGHT,
LABEL_HEIGHT);
[spinner startAnimating];
[self addSubview: spinner];
[self addSubview: label];
return self;
所以我的任务是创建一个带有微调器和“正在加载”字样的白色背景视图。我的方法是有效的还是有更好的方法来做到这一点?如果是这样,我将不胜感激。
亲切的问候
更新
解析为我获取数据的代码。
// Grab data for datasource and store in people array
NSLog(@"view will appear");
people = [[NSMutableArray alloc] init];
PFQuery *query = [PFQuery queryWithClassName:@"People"];
[query whereKey:@"active" equalTo:@1];
[query orderByDescending:@"createdAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error)
if (!error)
for (PFObject *object in objects)
// NSLog(@"%@", object);
Person *person = [[Person alloc] init];
[person setName:[object objectForKey:@"name"]];
[person setNotes:[object objectForKey:@"notes"]];
[person setAge:[[object objectForKey:@"age"] intValue]];
[person setSince:[object objectForKey:@"since"]];
[person setFrom:[object objectForKey:@"from"]];
[person setReferenceNumber:@"14-334544"];
PFFile *userImageFile = object[@"image"];
[userImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error)
if (!error)
UIImage *image = [UIImage imageWithData:imageData];
[person setImage:image];
];
[person setActive:[[object objectForKey:@"active"] intValue]];
[person setObjectId:[object objectId]];
[people addObject:person];
dispatch_async(dispatch_get_main_queue(), ^
[[self tableView] reloadData];
);
else
// Log details of the failure
NSLog(@"Error: %@ %@", error, [error userInfo]);
];
【问题讨论】:
您下载时使用的 Parse 方法是什么?是downloadInBackground
方法还是阻塞了它所在的线程?
是的,它是 findObjectsInBackgroudWithBlock
【参考方案1】:
您的所有 Parse 代码都是异步的,因此几乎可以立即完成。当视图实际出现时(在viewDidLoad
、viewWillAppear
、viewWillLayoutSubviews
和viewDidLayoutSubviews
全部完成之后),所有 Parse 代码都已完成,因为它会立即返回。
对于您正在寻找的效果,您应该阻止您的后台 Parse 线程。
例如,改变:
[userImageFile getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error)
if (!error)
UIImage *image = [UIImage imageWithData:imageData];
[person setImage:image];
];
到:
NSError *error;
NSData *imageData = [userImageFile getData:&error];
if (!error)
UIImage *image = [UIImage imageWithData:imageData];
[person setImage:image];
您需要类似地更改 [PFQuery -findObjectsInBackgroundWithBlock:]
以使用同步版本。
但是,请考虑另一种选择:不显示加载器,继续使用背景块,然后在数据进入时显示数据。这比显示加载器的体验要好得多。
tl;dr:您同时使用 GCD 异步块和 Parse 的背景块。只需使用其中一个即可。
【讨论】:
我考虑过使用替代方法,但我注意到在加载数据之前的一瞬间,我看到“标题”和“副标题”这两个词代替了实际数据的位置。这就是我想要一个装载机的主要原因。隐藏所有正在发生的事情。 只需在您的 xib/storyboard 中将这些字符串设置为空白即可。 您也可以在您的 awakeFronNib 方法中以编程方式更改它们。 前几天我在情节提要选项中尝试了这个。删除了子标题和标题中的文本,然后我的数据停止显示在表格中,所以我撤消了删除操作,它们再次显示。 我不想偏离主题(编辑标签将是一个单独的问题),但您应该能够做到这一点。删除文本后可能是帧大小的问题?无论如何,我相信我已经回答了这个问题。如果您想处理情节提要,您应该在此处标记一个答案已接受并为此发布一个单独的问题。【参考方案2】:由于您使用的是findObjectsInBackgroundWithBlock
,因此要在主线程上执行的代码会立即执行,并在找到对象时执行该块。您删除加载程序的代码应该在该块中已经存在的调度异步中执行:
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error)
// do something with the objects
dispatch_async(dispatch_get_main_queue(), ^
[[self tableView] reloadData];
// remove the loader
NSLog(@"downloading done.");
UIView *viewToRemove = [[self view] viewWithTag:17];
[viewToRemove removeFromSuperview];
);
];
关于在加载对象之前查看单元格的问题,您应该确保您正在重用单元格并且您的 tableViewController 的委托方法正确响应对象的数量,以便在您下载对象之前没有返回要放入 tableview 的数据。
【讨论】:
以上是关于我的 UIActivityIndicatorView 消失得太快,使其无用,延迟是解决此问题的最佳方法吗?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我的 UIActivityIndicator 在 UIButton 中以负 x 坐标作为子视图
UIActivityIndicatorView 不会在正确的时间停止
UIActivityIndicatorView 不工作(获取影响 UIActivityIndicatorView 的 Facebook 权限)
UIActivityIndicatorView 正确使用