I am trying to implement the UIRefreshControl in my application. I have an xib file and I added a UITableViewController to the empty nib file and I set the refresh property to "enabled". Also I have added code to the viewDidLoad and a custom refresh method. The problem is I have an error I can't find any information on....in my viewDidLoad I get "Property 'refreshControl' not found on object of type ViewController"
- (void)viewDidLoad{
[super viewDidLoad];
self.myTableView =
[[UITableView alloc] initWithFrame:self.view.bounds
style:UITableViewStyleGrouped];
self.myTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
self.myTableView.delegate = self;
self.myTableView.dataSource = self;
[self.view addSubview:self.myTableView];
UIRefreshControl *refresh = [[UIRefreshControl alloc] init];
refresh.attributedTitle = [[NSAttributedString alloc] initWithString:#"Pull to Refresh"];
[refresh addTarget:self action:#selector(refreshView:) forControlEvents:UIControlEventValueChanged];
self.refreshControl = refresh;
}
-(void)refreshView:(UIRefreshControl *)refresh {
refresh.attributedTitle = [[NSAttributedString alloc] initWithString:#"Refreshing data..."];
// custom refresh logic would be placed here...
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"MMM d, h:mm a"];
NSString *lastUpdated = [NSString stringWithFormat:#"Last updated on %#",
[formatter stringFromDate:[NSDate date]]];
refresh.attributedTitle = [[NSAttributedString alloc] initWithString:lastUpdated];
[refresh endRefreshing];
}
I have no idea why that property isn't available....what am I missing?
Looks like I need to inherit from UITableViewController in my ViewController.h file. If I already have UITableView there how do I inherit from both? If I change my code from ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> to ViewController : UITableViewController <UITableViewDelegate, UITableViewDataSource> then I get an error:
error: NSInternalInconsistencyException',
reason: '-[UITableViewController loadView] loaded the "ViewController_iPhone" nib but didn't get a UITableView.'
You can add UIRefreshControl as a subview to your UITableView.
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:#selector(handleRefresh:) forControlEvents:UIControlEventValueChanged];
[self.myTableView addSubview:refreshControl];
As per Dave's comment, this may break in future version of iOS. So please be careful while using this and try to raise a bug report to apple regarding this.
Update:
A better approach is by adding UITableViewController as a ChildViewController of self and then adding tableViewController.tableView as the subview of self.view. You dont have to do any hack to make it work in this way.
[self addChildViewController:tableViewController];
[self.view addSubview:tableViewController.tableView];
You can define the frame for tableView accordingly. Using this approach, UIRefreshControl should work in the same way as it works for UITableViewController.
`
Things to Remember:
UIRefreshControl only for UITableViewController, so your class should be the subclass of UITableViewController.
UITableViewController has a property refreshControl, you should allocate a UIRefreshControl
and set it to that property.
Ex:
UITableViewController *tableViewController = [[UITableViewController alloc] initWithStyle:UITableViewStylePlain];
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:#selector(refreshControlAction:) forControlEvents:UIControlEventValueChanged];
tableViewController.refreshControl = refreshControl;
All of these are complex ways of doing something simple.
You don't need to add a refresh control, or declare one in your viewController. Adding pull-to-refresh is a two-step process.
Step 1: In your storyboard, go to your tableViewController and, where it says "Refreshing", select "Enabled".
Step 2: Add the following code to your tableViewController.m file, in viewDidLoad:
[self.refreshControl addTarget:self
action:#selector(refresh)
forControlEvents:UIControlEventValueChanged];
That's the entire process, other than doing stuff in your -refresh method. When you want it to stop refreshing, call [self.refreshControl endRefreshing];.
Your ViewController class must be a subclass of UITableViewController in order to have access to the refreshControl property.
I would recommend you to make separate UITableViewController Subclass for myTableView.
And then by using addChildviewController or iOS6 ContainerView to add that class within original ViewController. That way even in the part of View, you can use UIRefreshControl.
Accepted answer is not official way, so it could break in future release as comment said...
Related
I have 2 UIViewControllers and I can pass values between them with no problem. The problem comes when I try to pass a value to a third view (a UITableViewController).
Here is my code
All the connections are set correctly, the tableview gets called here:
- (IBAction)goToTableView:(id)sender {
TableMovieViewController *vc=[self.storyboard instantiateViewControllerWithIdentifier:#"TableMovieViewController"];
vc.finalResult.text=stringFromFirstView;
[self presentViewController:vc animated:YES completion:nil];
}
The vc.finalResult.text has by example "Test Call", I verified and the value is there.
Now on the table view file:
.h file:
#property(strong, nonatomic)UITextField *finalResult;
.m file:
#synthesize finalResult;
- (void)viewDidLoad
{
[super viewDidLoad];
UINavigationBar *nav = [[UINavigationBar alloc]initWithFrame:CGRectMake(0, 0, 320, 40)];
UINavigationItem *navItem = [[UINavigationItem alloc] initWithTitle:finalResult];
[nav pushNavigationItem:navItem animated:FALSE];
[self.view addSubview:nav];
}
The finalResult never gets set with the value passed from the previous view.
Any ideas
Thanks
Rodrigo
Change:
UINavigationItem *navItem = [[UINavigationItem alloc] initWithTitle:finalResult];
With:
UINavigationItem *navItem = [[UINavigationItem alloc] initWithTitle:finalResult.text];
finalResult is of type UITextField and not NSString.
initWithTitle: asks for a NSString and not a UITextField as you are setting now.
EDIT:
As I read the edit that was meant as a comment on my answer you say that the UITextField *finalResult is a nil-value. This is probably because you did not allocate and ininitialise the UITextField as you should.
You need to do the finalResult = [[UITextField alloc] init]; at least BEFORE the place you set the text of it. I suggest you do it in the init function of the UITableViewController.
I have created a UIRefreshcontrol without a TableViewController. My question is how I would end it inside another method?
This is how I created it;
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:#selector(handleRefresh) forControlEvents:UIControlEventValueChanged];
[_tableView addSubview:refreshControl];
I discovered with help from #Justin Paulsson that this could be done;
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:#selector(handleRefresh:) forControlEvents:UIControlEventValueChanged];
[_tableView addSubview:refreshControl];
-
-(void) handleRefresh:(UIRefreshControl *)controller
{
//Refresh code
controller.endRefreshing;
}
The documented way is using an UITableViewController. Anything else can work, but as it's not documented, it may break on next iOS versions.
I'd just use an UITableViewController in your case.
It turns out that UIRefreshControl doesn't require a UITableView at all. refreshControl is a property of UIScrollView. You can set it on anything that inherits from UIScrollView, which includes UITableView of course, but also other classes such as UICollectionView.
I have a weird problem. I have a tab bar application. When I wanna set the text of an UILabel in any method, there happens nothing.
For example, nothing happens with 'label1' when I call this method:
-(void)setOne:(NSMutableArray *)theArray {
label1 = [[UILabel alloc] init];
label1.text = #"Test";
}
Does anyone have a solution for this problem?
Thanks,
Jelle
When you call this method a new label is created and the connection to the label which was previously associated with this ivar is lost. This could also be a memory leak.
Edit:
Depending on the rest of your code, this could work:
-(void)setOne:(NSMutableArray *)theArray {
label1.text = #"Test";
}
You don't see anything happened because you create new instance of label and do not add it anywhere. If you really want to add new label to your view then create it with appropriate frame and actually add it to some view, e.g.
-(void)setOne:(NSMutableArray *)theArray {
label1 = [[UILabel alloc] initWithFrame:CGRectMake(10.0f, 10.0f, 200.0f, 30.0f)];
label1.text = #"Test";
[self.view addSubview: label1];
// And do not forget to release your label!
[label1 release];
}
If you want to change text of label that already exists do not create new instance in your method, just set new text to it:
-(void)setOne:(NSMutableArray *)theArray {
// if label1 already exists we don't need to create a new one
label1.text = #"Test";
}
Edit: (from more info in comments)
When you create view controller it may not load its view immediately so in your code
FirstViewController *FVC = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
[FVC setOne:[resultaten objectAtIndex:indexPath.row]];
when you call setOne method fvc's view may still not be loaded and label1 is still nil in that method. You can solve that forcing controller's view to load, the following should work:
FirstViewController *FVC = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
FVC.view;
[FVC setOne:[resultaten objectAtIndex:indexPath.row]];
But in general I'd suggest to store your values in some class that's independent from UI (i.e. Model) or at least in separate variable of your controller and set it to UI elements only when they actually loaded or appear on screen (in viewDidLoad or viewWillAppear methods)
- (void)viewDidLoad
{
[super viewDidLoad];
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 200, 22)];
lbl.text =#"Hello";
[self.view addSubview:lbl];
}
I have a UIViewController which has a grouped UITableView as a property. I instantiate the UITableView in code and don't use IB. I would like to hook up a UISearchDisplayController to it but can't find any example how this could be done.
This what I have.
//Have implemented the UISearchDisplayDelegate in the header file
//SearchBar
UISearchBar *searchBar = [[UISearchBar alloc]initWithFrame:CGRectMake(0, 0, 320, 45)];
searchBar.barStyle=UIBarStyleBlackTranslucent;
searchBar.showsCancelButton=NO;
searchBar.autocorrectionType=UITextAutocorrectionTypeNo;
searchBar.autocapitalizationType=UITextAutocapitalizationTypeNone;
searchBar.delegate=self;
UISearchDisplayController *mySearchDisplayController = [[UISearchDisplayController alloc ]initWithSearchBar:searchBar contentsController:self];
self.searchDisplayController = mySearchDisplayController; //Error here ?? self.searchDisplayController is ReadOnly and can't assign
[self.searchDisplayController setDelegate:self];
[self.searchDisplayController setSearchResultsDataSource:self];
[mySearchDisplayController release];
[myDisplayController release];
This doesn't seem to work, the searchDisplayController propery of the UIViewController seems to be readonly and I can't hook myDisplayController onto it. I'm really not sure if this the right way to do it.
I've been looking all around google to find some tip or tutorial on how to use a UISearchDisplayController in UIViewController. All the examples I could find was how to implement it into UITableViewController using IB, which is not the way I want to use it.
Can anyone explain how I could get this working ?
Here's the code that I use. Put this in viewDidLoad of a UIViewController that instantiates it's own UITableView. I think the part you're looking for is to add the search bar as the header view of the table view.
UISearchBar * theSearchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0,0,320,40)]; // frame has no effect.
theSearchBar.delegate = self;
if ( !searchBarPlaceHolder ) {
searchBarPlaceHolder = #"What are you looking for?";
}
theSearchBar.placeholder = searchBarPlaceHolder;
theSearchBar.showsCancelButton = YES;
self.theTableView.tableHeaderView = theSearchBar;
UISearchDisplayController *searchCon = [[UISearchDisplayController alloc]
initWithSearchBar:theSearchBar
contentsController:self ];
self.searchController = searchCon;
[searchCon release];
searchController.delegate = self;
searchController.searchResultsDataSource = self;
searchController.searchResultsDelegate = self;
[searchController setActive:YES animated:YES];
[theSearchBar becomeFirstResponder];
See the Apple Docs:
#property(nonatomic, readonly, retain) UISearchDisplayController *searchDisplayController
Discussion: This property reflects the value of the
searchDisplayController outlet that you set in Interface Builder. If
you create your search display controller programmatically, this
property is set automatically by the search display controller when
it is initialized.
I'm trying to create a tableview with a searchbar inside the header view of the table. I'd like to use a searchDisplayController to manage everything.
I've created everything programmatically (I'm not feeling comfortable with IB) trying to set all the correct properties, but it seems that I'm missing something, because when the table shows up I'm not able to edit the text in the searchbar and see any animation.
Here is a part of the code:
- (void)viewDidLoad {
[super viewDidLoad];
UISearchBar *searchBarTMP=[[UISearchBar alloc]init];
self.searchBar=searchBarTMP;
[searchBarTMP release];
self.searchBar.autocapitalizationType=UITextAutocapitalizationTypeNone;
self.searchBar.delegate=self;
self.searchBar.showsScopeBar=YES;
self.searchBar.keyboardType=UIKeyboardTypeDefault;
self.searchBar.userInteractionEnabled=YES;
self.searchBar.multipleTouchEnabled=YES;
self.searchBar.scopeButtonTitles=[NSArray arrayWithObjects:NSLocalizedString(#"City",#"Scope City"),NSLocalizedString(#"Postal Code",#"Scope PostalCode"),nil];
self.tableView.tableHeaderView=searchBar;
self.searchBar.selectedScopeButtonIndex=0;
self.navigationItem.title=NSLocalizedString(#"Store",#"Table title");
//SearchDisplayController creation
UISearchDisplayController *searchDisplayControllerTMP = [[UISearchDisplayController alloc] initWithSearchBar:self.searchBar contentsController:self];
self.searchDisplayController=searchDisplayControllerTMP;
[searchDisplayControllerTMP release];
self.searchDisplayController.delegate=self;
self.searchDisplayController.searchResultsDelegate=self;
self.searchDisplayController.searchResultsDataSource=self;
//....continue
}
I know that when you use a searchbar alone you must deal with its delegate protocol, but I'm guessing that the searchDisplayController manage for you as seen in the Apple sample code. (build up with IB).
Any suggestion?
Thank you,
Andrea
Found it...
After putting in the header of the table view must write
[self.searchBar sizeToFit];
If you are using ARC, make sure you create an iVar for the UISearchDisplayController in your header file.
If you create an UISearchDisplayController using:
UISearchDisplayController* searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:searchField contentsController:self];
it will get released by ARC, it will not call any delegate methods and when you'll call self.searchDisplayController (the UIViewController's property) it will be nil.
So, the fix is:
In your header (.h) file:
#interface MenuViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate, UISearchDisplayDelegate> {
UISearchDisplayController* searchDisplayController;
UISearchBar *searchField;
UITableView* tableView;
NSArray* searchResults;
}
and in the implementation (.m) file:
searchField = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 49)];
searchField.delegate = self;
searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:searchField contentsController:self];
searchDisplayController.delegate = self;
searchDisplayController.searchResultsDataSource = self;
searchDisplayController.searchResultsDelegate = self;
tableView.tableHeaderView = searchField;
tableView.contentOffset = CGPointMake(0, searchField.frame.size.height);
When implemented like that, you can call both self.searchDisplayController and searchDisplayController in the rest of your code.