UIRefreshControl crashes while refreshing Tableview Controller - iphone

I can't refresh my TVC. It crashes when I drag down to refresh. The icon is there, but then it quits. I'm sure its something simple. There are similar questions out there which have not been considered.
Taken from my viewDidLoad method body:
refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self
action:#selector(refreshInvoked:forState:)
forControlEvents:UIControlEventValueChanged];
[self.tableView addSubview:refreshControl];
refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString:title
attributes:#{NSFontAttributeName:[UIFont fontWithName:#"Helvetica" size:13.0]}];
[self refreshFeed];
Which refers to:
-(void)refreshFeed
{
RSSLoader* rss = [[RSSLoader alloc] init];
[rss fetchRssWithURL:feedURL
complete:^(NSString *title, NSArray *results) {
dispatch_queue_t downloadQueue = dispatch_queue_create("downloader",NULL);
dispatch_async(downloadQueue, ^{
_objects = results;
[self.tableView reloadData];
//completed fetching the RSS
dispatch_async(dispatch_get_main_queue(), ^{
// [(HeaderView*)self.tableView.tableHeaderView setText:title];
// [(ArticleItem*)self.tableView.]
});
});
}];
}

UIRefreshControl is not meant to be added as subview... doing so will get you some trouble and you need to unregister its target on VC dealloc... else you might get some issues, when the UIRefreshControl calls your dead VC (as it doesn't keep a weak or strong reference to your VC)

Change your action method to:
[refreshControl addTarget:self
action:#selector(refreshFeed)
forControlEvents:UIControlEventValueChanged];
Looks like you were pointing to refreshInvoked:forState: which was not present in self.

Related

UIActivityIndicatorView doesn't render

I have reviewed many posts regarding this issue with no success. I have two table view controllers, a source and a destination, both in a navigation controller. When a user taps a cell in the source table view controller, an object is instantiated which makes a web service call that could take several seconds depending on network speed. Once this web service call is made, the segue is executed and navigation moves from the source to the destination. I want an activity indicator to show when this web service call is made. Nothing I have tried for the past several days has worked, even posts marked as successful on this forum. So, there must be something... Here is my code thus far:
Source table view controller header:
#property (strong, nonatomic) UIActivityIndicatorView *activityIndicator;
Source table view controller implementation:
#synthesize activityIndicator;
-(void)loadView {
[super loadView];
self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[self.view addSubview:self.activityIndicator];
self.activityIndicator.center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2);
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
NSString *stateAbbr;
if([segue.identifier isEqualToString:#"sgShowStateDetail"]){
DetailTableViewController *detailVC = [segue destinationViewController];
NSIndexPath *path = [self.tableView indexPathForSelectedRow];
NSArray *tempArray = (NSArray*)[groupedStates objectAtIndex:path.section];
NSString *key = [tempArray objectAtIndex:path.row];
stateAbbr = [statesDict objectForKey:key];
[detailVC setStateIdentifier:stateAbbr];
// begin activity indicator here
[self.view bringSubviewToFront:activityIndicator];
[activityIndicator startAnimating];
gauges = [[GaugeList alloc] initWithStateIdentifier:stateAbbr andType:nil];
[activityIndicator stopAnimating];
[detailVC setStateGauges:gauges];
// end activity indicator here
}
}
GaugeList is the object that performs the web service call.
Everything works as expected, except there is never an activity indicator. There are no errors. What am I doing wrong? Thanks!
I think you might be using the wrong pattern. The call to the web service has to happen in the background, while the activity indicator has to be shown and hidden on the main thread. Thus
__block NSArray *gauges;
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
gauges = [[GaugeList alloc] initWithStateIdentifier:stateAbbr andType:nil];
dispatch_async(dispatch_get_main_queue(), ^{
[activityIndicator stopAnimating];
[detailVC setStateGauges:gauges];
};
};
Here is the code using the method tableView: didSelectRowAtIndexPath: rather than prepareForSegue:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.view bringSubviewToFront:activityIndicator];
[activityIndicator startAnimating];
dispatch_async(dispatch_queue_create("", nil), ^ {
NSString *stateAbbr;
DetailTableViewController *detailVC = [self.storyboard instantiateViewControllerWithIdentifier:#"DetailTableViewController"];
NSArray *tempArray = (NSArray*)[groupedStates objectAtIndex:indexPath.section];
NSString *key = [tempArray objectAtIndex:indexPath.row];
stateAbbr = [statesDict objectForKey:key];
[detailVC setStateIdentifier:stateAbbr];
gauges = [[GaugeList alloc] initWithStateIdentifier:stateAbbr andType:nil];
[detailVC setStateGauges:gauges];
dispatch_async(dispatch_get_main_queue(), ^{
[activityIndicator stopAnimating];
[self.navigationController pushViewController:detailVC animated:YES];
});
});
}

UIRefreshControl hangs indefinitely

I have a UIRefreshControl, and it works fine when you use it, but it hangs, it never goes away. I've tried
[self.refreshControl endRefreshing];
This solution was from a similar question, but it has not addressed mine.
Even with this, the refreshControl continues spinning, not dismissing. Why is this?
In my viewDidLoad:
[NSThread detachNewThreadSelector:#selector(refreshFeed) toTarget:self withObject:nil];
refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self
action:#selector(refreshFeed)
forControlEvents:UIControlEventValueChanged];
[self.tableView addSubview:refreshControl];
refreshFeed method...
-(void)refreshFeed
//load those feeds
{
RSSLoader* rss = [[RSSLoader alloc] init];
[rss fetchRssWithURL:feedURL
complete:^(NSString *title, NSArray *results) {
dispatch_queue_t downloadQueue = dispatch_queue_create("downloader",NULL);
dispatch_async(downloadQueue, ^{
_objects = results;
//completed fetching the RSS
dispatch_async(dispatch_get_main_queue(), ^{
[self.refreshControl endRefreshing];
[self.tableView reloadData];
});
});
}];
}
Can you try changing this line
[self.tableView addSubview:refreshControl];
with
[self setRefreshControl:refreshControl];

Display navigationController on top

I have set up a subview "popup" in my application and I want to show a navController if the user taps a button on the subview popup. I've set up the button so far, but if I tap the button the navigationController appears under my popup!? I've searched for some solution but I didn't found any. The whole controller is actually displayed in a folder which you can find here: https://github.com/jwilling/JWFolders So the viewDidLoad belong to the folder and the rootview.
I tried to make it as a subview of the popup but that doesn't work too. Does anyone know how to treat that? I've set up the popup programmaticaly and the navigationController too.
Thanks in advance.
My code:
The navController setup:
- (IBAction)dothis:(id)sender {
MWPhotoBrowser *browser = [[MWPhotoBrowser alloc] initWithDelegate:self];
// Set browser options.
browser.wantsFullScreenLayout = YES;
browser.displayActionButton = YES;
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:browser];
[self presentModalViewController:navController animated:YES];
NSMutableArray *photos = [[NSMutableArray alloc] init];
MWPhoto *photo;
photo = [MWPhoto photoWithFilePath:[[NSBundle mainBundle] pathForResource:#"star" ofType:#"png"]];
photo.caption = #"The star is soo beateful...";
[photos addObject:photo];
self.photos = photos;
}
- (MWPhoto *)photoBrowser:(MWPhotoBrowser *)photoBrowser photoAtIndex:(NSUInteger)index {
if (index < _photos.count)
return [_photos objectAtIndex:index];
return nil;
}
- (NSUInteger)numberOfPhotosInPhotoBrowser:(MWPhotoBrowser *)photoBrowser {
return _photos.count;
}
The popup code:
-(IBAction)mehr:(id)sender {
//the popup size and content
UIView *contentView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 280, 440)];
CGRect welcomeLabelRect = contentView.bounds;
welcomeLabelRect.origin.y = 20;
welcomeLabelRect.size.height = 40;
UILabel *welcomeLabel = [[UILabel alloc] initWithFrame:welcomeLabelRect];
//an simple activityindicator
activityindi = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
activityindi.frame = CGRectMake(120, 200, 40, 40);
[activityindi startAnimating];
[contentView addSubview:activityindi];
//The Imageview
CGRect infoimagerect = CGRectMake(5, 70, 270, 200);
UIImageView *infoimage = [[UIImageView alloc] initWithFrame:infoimagerect];
//and the Button
cubut = [UIButton buttonWithType:UIButtonTypeCustom];
[cubut addTarget:self
action:#selector(dothis:)
forControlEvents:UIControlEventTouchUpInside];
[cubut setTitle:nil forState:UIControlStateNormal];
cubut.frame = CGRectMake(5, 70, 270, 200);
//retrieving data from parse.com
PFQuery *query = [PFQuery queryWithClassName:#"My-Application"];
[query getObjectInBackgroundWithId:#"My-ID"
block:^(PFObject *textdu, NSError *error) {
if (!error) {
//hide the Button if there is no image
cubut.hidden=YES;
//the headline of popup
UIFont *welcomeLabelFont = [UIFont fontWithName:#"copperplate" size:20];
welcomeLabel.text = [textdu objectForKey:#"header"];
welcomeLabel.font = welcomeLabelFont;
welcomeLabel.textColor = [UIColor whiteColor];
welcomeLabel.textAlignment = NSTextAlignmentCenter;
welcomeLabel.backgroundColor = [UIColor clearColor];
welcomeLabel.shadowColor = [UIColor blackColor];
welcomeLabel.shadowOffset = CGSizeMake(0, 1);
welcomeLabel.lineBreakMode = UILineBreakModeWordWrap;
welcomeLabel.numberOfLines = 2;
[contentView addSubview:welcomeLabel];
//the image from parse
if (!error) {
PFFile *imageFile = [textdu objectForKey:#"image"];
[imageFile getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
UIImage *image = [UIImage imageWithData:data];
infoimage.image = image;
infoimage.contentMode = UIViewContentModeScaleAspectFit;
//show the button when the image appears
cubut.hidden = NO;
[contentView addSubview:infoimage];
//stop the activityindicator
[activityindi stopAnimating];
}
}];
}
} else {
//show some text
welcomeLabel.text = #"No connection!";
[welcomeLabel sizeToFit];
//hide the button
cubut.hidden = YES;
[contentView addSubview:infoLabel];
//stop the activityindicator
[activityindi stopAnimating];
}
}];
//add the content to the KNGModal view
[[KGModal sharedInstance] showWithContentView:contentView andAnimated:YES];
}
My viewDidLoad
- (void)viewDidLoad
{
but.hidden = YES;
PFQuery *query = [PFQuery queryWithClassName:#"myapp"];
[query getObjectInBackgroundWithId:#"Rgq5vankdf"
block:^(PFObject *textu, NSError *error) {
if (!error) {
but.hidden = NO;
but.color = [UIColor colorWithRed:0.90f green:0.90f blue:0.90f alpha:1.00f];
} else {
//if failure
but.hidden = YES;
mol.text = #"No Connection";
}
}];
[super viewDidLoad];
}
Pictures:
The button to open the folder:
The folder itself:
The popup:
Thanks in advance.
From the so far discussion and debugging the code you want to have the photo browser on the pop-up with a navigation controller.
So here is the sample code which implements this functionality, have a look at it.
I have used the same KGModal sample code and extended as per the requirement. I have used Xib to have a view with navigation bar.
To dismiss the pop-up from any where in the app you can use the below line, as it is shared instance.
[[KGModal sharedInstance] hideAnimated:YES];
Update:
The reason for showing the photo browser with in folderView is, you are trying to present the photoBrowser within the folderView, so it was presenting within the folderView of very small height & not able to see any photo.
So my suggestion is, as the user taps on pop-up to view photoBrowser you just remove pop-up and present the photoBrowser from the viewController class, as other than this class everything is handled through views.
I have made the changes as per above & works fine, to the code given by you, download the code here and have a look at it.
Let me know if it fulfills your needs.
Thanks
I noticed this line of code:
[[KGModal sharedInstance] showWithContentView: contentView andAnimated: YES];
And I can only think that, since it is a singleton, it adds the contentView on the UIApplication's key window. If that is the case, then a modal view controller will always be below the popup. You can solve this by adding a new method to the KGModal class
- (void) showWithContentView: (UIView*) contentView
inViewController: (UIViewController*) controller
andAnimated: (BOOL) animated;
the method should show the popup in the specified controller's view; you should use that method instead.
Edit
After some more digging, I found that KGModal displays the popup on another window. The quickest fix would be to dismiss the popup, then show the nav controller.

Hide UIPickerview On Done Button in UITableView

I have UITextField in each Cell of UITableview and I have added UIPickerview as inputView of UITextField and showing with Done button at its tool bar
My question is how can I hide this this pop up (Picker + toolbar) on click of done button ?
and show selected value of picker in text box in particular cell ?
Thanks and Regards
Edit : Code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
PremiumProductsDescriptionCell *cell = (PremiumProductsDescriptionCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[PremiumProductsDescriptionCell alloc] initShoppingCartCellWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
ShopProduct *p = (ShopProduct *)[[ShopProduct GetShoppingCart] objectAtIndex:indexPath.row];
cell.Quantity.text = [NSString stringWithFormat:#"%d",p.Quantity];
UIPickerView *quantityPicker = [[UIPickerView alloc] init];
quantityPicker.dataSource = self;
quantityPicker.delegate = self;
UIToolbar *myToolbar = [[UIToolbar alloc] initWithFrame:
CGRectMake(0,0, 320, 44)];
UIBarButtonItem *doneButton =
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self action:#selector(hideKeyBoard)];
quantityPicker.tag = indexPath.row;
[myToolbar setItems:[NSArray arrayWithObject: doneButton] animated:NO];
cell.Quantity.inputAccessoryView = myToolbar;
cell.Quantity.inputView = quantityPicker;
cell.Quantity.delegate = self;
return cell;
}
Solved :
I have taken currentTextBox a variable and added following method and resizing its first responder in done button's click :)
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
currentTextBox = textField;
}
UIPopOver cant be dismissed from their class and you need to dismiss it from the calling class.
You have to call dismiss method from popover calling class, when user presses the done button
-(void)doneButtonClikd
{ ParentClass *viewController=[ParentClass alloc]init];
[viewController dismissPopOver];
}
I think this will solve your problem
For your inputview-
-(void)doneButtonclikd
{ [selectedTextfield resignFirstResponder];
}
Dont forget to save the currently selected textfield.
Assuming you put the UIPickerView in a popover, here's how to do it:
UIPopoverController* popover = ....
UIBarButtonItem* doneButton = ....
[doneButton addTarget:self action:#selector(closeMe)
forControlEvents:UIControlEventTouchUpInside]
// ....
- (void)closeMe
{
// Assuming popover is really a field or something...
[popover dismissPopoverAnimated:YES];
}
Use [self.view endEditing:YES] method.

UITableView addSubview and table lines

I'm trying to add a custom view to an UITableView created with code from an UITableViewController. This view is a HUD window with a message (MBProgressHUD)
So I have a method reload() called from the overridden initWithStyle() method and from the refresh button of the table:
- (void) reload {
HUD = [[MBProgressHUD alloc] initWithView:self.tableView];
[self.view addSubview:HUD];
HUD.delegate = self;
HUD.labelText = #"Downloading";
[HUD showWhileExecuting:#selector(reloadWithHUD) onTarget:self withObject:nil animated:YES];
}
The first time, the HUD appears behind the table lines. Once loaded, when I press reload button, the view shows as expected. The initWithStyle() method (with some code removed for clarity) is:
- (id)initWithStyle:(UITableViewStyle)style {
self = [super initWithStyle:style];
if (self) {
// Custom initialization.
self.title = NSLocalizedString...
UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithTitle ... action:#selector(reload)];
self.navigationItem.rightBarButtonItem = button;
[button autorelease];
[self reload];
}
return self;
}
I've tried changing the HUD view with a simple UILabel, with the same result.
I also changed the code to call reload() from viewDidLoad(), but doesn't work either. How can I resolve this issue? Thank you very much.
EDIT : to clarify this, here is a possible solution to this problem. Many thanks to Bill Brasky for his help:
HUD = [[MBProgressHUD alloc] initWithView:self.view];
[[[UIApplication sharedApplication] keyWindow] addSubview:HUD];
Here is what I'm doing in my app with an almost identical application.
You need to add it to the main view WINDOW, not the tableView.
HUD = [[MBProgressHUD alloc] initWithView:self.view.window];
[self.view.window addSubView:HUD];
My project is based on IOS 7
This helps me
[self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];