I know this is a startlingly stupid question, but I can't figure it out. Every answer involves a UISearchBar, which is not what I've got.
I'm trying to display 2 sets of results on one TableViewController.
Results to display
1) everything in my managedObjectContext which is set up in my viewDidLoad
2) a filtered set of results if a predicate is selected.
On MyTableViewController, I have a popover which instantiates when I click a UIBarButtonItem on MyTableViewController. On the popover, I set a predicate on MyTableViewController.
Basically, I'd like to toggle what's displayed and that display toggle is driven by whether my variable is nil (everything displays) or filtered (variable sets a predicate).
Have two NSArray properties allValues and filteredValues. Set up all your delegate/dataSource properties using your filteredValues array.
Next, do something like this when you first get all your data:
self.allValues = [someController fetchAllValues];
self.filteredValues = self.allValues;
[self.myView.tableView reloadData];
Last, alter your filteredValues array whether or not a predicate is selected:
if (self.selectedPredicate) {
self.filteredValues = [self.allValues filteredArrayUsingPredicate:self.selectedPredicate];
} else {
self.filteredValues = self.allValues;
}
[self.myView.tableView reloadData];
Related
I have tried to hide my tableView when it's empty using following line of code inside of the viewDidAppear and viewDidLoad methods:
let count = self.fetchedResultsController.fetchedObjects?.count == 0
self.tableView.isHidden = count
But it's doesn't work.
How to hide a tableView when it's empty?
Do you really need to hide the table when it's empty?
I would rather provide one big table row with information like 'No results found' or something.
But if you need to display other UI stuff when no results:
Try to use the function with fetchRequest.
let count = managedContext.countForFetchRequest(fetchRequest, error: nil) == 0
1) I am working on one application which contains one single tableview and above that tableview there is one horizontal scrollview which contains number of dynamic button eg.button1,button2....
2)On touch of each button json is comming and i am parsing and showing that json in tableview using NSURLSession.eg.One touch of button1 json will come,on touch of button2 different json will come.
3)After that i want to store each button json array into single array and display accordingly.eg. suppose i clicked on button2 json will come and should be stored in array so that in future i retouch that button data should come from stored array.
I've managed point 1 & 2 but not getting any idea how to solve 3 point.
I also added the one image which will give clear understanding about my problem.
Please if any one have idea then reply to this question.Thanks in advance.
You can use NSCache to cache items if you want, it works like an NSDictionary.
// Init NSCache and declare somewhere as property//you must use singleton approach as well, it's just example i have initialized in viewDidLoad
- (void)viewDidLoad
{
self.cache = [NSCache alloc] new];
}
-(void)callApiForKey:(NSString *)buttonName{
id aObject = [self.cache objectForKey:buttonName]
if aObject == nil {
//perform the API call you are talking about
//after the fetch is preformed and you get data...
[self.cache setObject: dataObject forKey:buttonName];
//perform what you need to with said object
} else {
//perform operation with cached object
}
}
USES:
on your button click action call above method with buton text:
yourButton.titleLabel.text.
[self callApiForKey:yourButton.titleLabel.text];
be suer keys must be unique. other wise you may get/set wrong data obviously.
Thanks
-Each button have a unique tag right? Like button 1 have tag 1, button 2 have tag 2 ,button 3 have tag 3,
-you can manage this thing by Global nsmutabledictionary and nsmutableArray.
-if you click on button 1 before api calling you check
if(dictionary valueforkey:#"1") (1mean selected button tag)
{
no need to call api
no need to add array in dictionary
array=[[dictionary valueforkey:#"1"]mutablecopy];(1mean selected button tag)
[tble reloaddata];
}
else
{
api calling
here you can add array in dictionary
[dictionary setobject:yourarray forkey:#"1"];
array=[[dictionary valueforkey:#"1"]mutablecopy];(1mean selected button tag)
[tble reloaddata];
}
Please don't mark this as a duplicate question because I have found no suitable answer for my query.
I have a table view with cells that contain text fields. I have a button at the bottom of the screen. The number of rows is greater than the screen can display, so some cells are not in view. I want that at any point when the button is pressed, all textfields be read and the text input be processed. I am unable to do so because apparently because of the reusability of cells, cells out of view do not exist at all and cellForRowAtIndexPath for those indexPaths gives a runtime error. I have read answers that say that this simply can't be done. But I find it hard to believe that there is no workaround to this. Please help. Thanks in advance!
This definitely can't shouldn't be done (accessing cells that are off screen, or implementing workarounds to allow it), for reasons of (at least) performance and memory usage.
Having said that there is, as you put it, a workaround. What you will need to do it change how you are storing the values in those text fields. Rather than iterating through cells and retrieving the text directly from the text fields you should store the text for each field in an collection.
Define a dictionary property on your table view controller / data source to hold the text for each row.
Act as the delegate of UITextField and assign as such in tableView:cellForRowAtIndexPath:
Implement textField:didEndEditing: (or whatever is appropriate for your use case) and store the text in the dictionary keyed against the index path relating to the cell that contains that text field.
Update the button action method to use this dictionary instead of iterating through cells.
Create a UITableViewCell subclass, add your tableViewCells a index property and introduce a delegate like:
protocol CustomCellDelegate {
func didEditTextField(test : String, atIndex : Int)
}
Create a delegate variable on your UITableViewCell subclass.
var delegate : CustomCellDelegate?
Implement the UITextViewDelegate in your tableViewCell and set the cell to be the delegate of your textfield.
Implement these two methods:
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
func textFieldDidEndEditing(textField : UITextField) {
// call back with the delegate here
// delegate?.didEditTextField(textfield.text, atIndex: self.index)
}
So when the user ends editing the textField, your cell will call out with a delegate, sending the text and the index.
On your viewController, when you init your tableViewCell, set the delegate of the cell to the viewController, and set the index to indexPath.row .
Set up on your viewController a String array with as many items as many tableViewCells you got. Init the array with empty strings.
So you got the delegate on your viewController, and whenever it is called, you just insert the returned text to right index in the string array on your viewcontroller.
What do think, will this work?
If we can assume that cells that have NEVER been created has no text inputs, then create an Array or Set ourselves and clone the content/input texts there whenever user inputs to a cell's textfield.
Whenever, that button is clicked, you can iterate the array instead of cells to get all the inputs.
This is a bit hacky though..
In the settings section of my app the user has the option to change the language of the app. So when the user chooses spanish as his primary language the app show the content in spanish after he did an app restart but I want to change the language on the fly. This works for the main content like a TableView because I simply can reload the data but the language in my TabBarController does not change because I don't know how.
So I want to update (or better call it a reset) the TabBarController. After the reset it should display all navigation points in the new language.
My idea was to remove the current TabBarController and initialize a new one. Is this possible? Or is there a better way?
I am not an native english speaker so if my explanations aren't clear enough, just tell me and I'll try to rephrase them.
It might look scary and complicated because of my long post, But it really isn't, it is just long because I thought it would be better to also explain how to do it, instead of just giving a few lines of code.
You can achieve what you want using UITabBarController properties.
UITabBarController have a property called tabBar, which is the actual UITabBar.
One might think that in order to achieve what you want, you should edit this property,
HOWEVER, editing this property would cause an exception.
From apple's UITabBarController documentations, regarding the tabBar property:
You should never attempt to manipulate the UITabBar object itself stored in
this property. If you attempt to do so, the tab bar view throws an exception.
So you should never attempt to edit this property at runtime.
After that word of warning, here is what you should do-
UITabBarController also have a property called viewControllers, which is an NSArray who holds reference to the view controllers that being displayed by the tab bar.
This property CAN be modified at runtime, and changes applied to it are updated instantly in the tab bar.
However, for your case, you don't need to modify this property,
But I thought you should know that so if in some situation you will need to add or remove some items from your tab bar, you'll know that can do it.
What you do want to do, is iterate through the objects of that array to access the view controllers themselves.
UIViewController have a property called tabBarItem which represents the UITabBarItem of the view controller.
So what we are basically doing, is getting the tab bar item of the view controller, but instead of getting it from the UITabBarController itself, we are getting it directly from each view controller.
Each UITabBarItem has a title property, and this is what you want to change.
So now, after that long introduction, let's get to the actual code.
I think a pretty easy way to achieve what you want is to iterate thru the viewControllers array, and have some switch statement in there that would change the title.
As in any programming situations, this can be done in countless other ways, so you might have a better way to implement it than my example below, but this should do the trick.
Each view controller that being displayed in a tab bar controller, have a reference to that tab bar using the property tabBarController
So you can run this code in any of the view controllers that being displayed in the tab bar, and simply use self.reference to get a reference to it.
Add this somewhere after the language have changed-
for (int i = 0; i < [self.tabBarController.viewControllers count]; i++) {
if([self.tabBarController.viewControllers[i] isKindOfClass: [UIViewController class]]) {
UIViewController *vc = self.tabBarController.viewControllers[i];
switch(i) {
case 0:
vc.tabBarItem.title = #"primero";
break;
case 1:
vc.tabBarItem.title = #"secondo";
break;
}
}
}
What we are basically doing, is running a for loop that iterating thru all of the items in the array,
The items in the array are in the same order that they appear on the tab bar,
then we use a switch statement to change the title for the view controller in the corresponding position,
Since array have index 0, the first view controller is at position i=0 and the last one is at one less than the count of items in the array.
Some might argue that my if is unnecessary,
Since we already know that this array holds only view controllers, there is no need to check if the item at that position is of UIViewController class, or a subclass of it.
They might be right, but I always say it's better to be safe than sorry.
Of Curse I would also include in your code something to actually check to what language the user have chosen.
The example above changes the titles to spanish, regardless of the user's choice.
Hope it helps mate,
Good luck
#AMI289 gave a good idea.
Make an extension for UITabBarController and do a loop there. Can call anywhere from the tabBarControllers stack.
In my case after the tabBarController goes navigationController.
// MARK: - UITabBarController
extension UITabBarController {
func changeTitleLocale() {
guard let viewContollers = self.viewControllers else { return }
for (index, navVC) in viewContollers.enumerated() {
if let view = navVC as? UINavigationController {
if let topView = view.topViewController {
if topView.isKind(of: ProfileVC.self) {
self.tabBar.items?[index].title = "tab_profile"
} else if topView.isKind(of: ChatVC.self) {
self.tabBar.items?[index].title = "tab_chat"
} else if topView.isKind(of: PicturesVC.self) {
self.tabBar.items?[index].title = "tab_pictures"
} else if topView.isKind(of: VideosVC.self) {
self.tabBar.items?[index].title = "tab_videos"
}
}
}
}
}
}
Then, when we change a language just run it:
self.tabBarController?.changeTitleLocale()
I´m using a table view to display different types of items. The view controller for the table is always the same, ItemsViewController.
I have a menu with buttons for each type of item. Depending on what button the user clicks, a specific array of items must be used to populate the table view.
My solution:
Every item has an typeId property. When a type button is clicked, the following method is called:
[self.itemController createItemListForId:buttonPressed.typeId];
where buttonPressed is, well, the pressed menu button.
This is the implementation for createItemListForId:
-(void)createItemListForId:(int)theId{
for (Item *item in self.masterItemList){
if(item.typeId == theId){
[self.itemList addObject:item];
}
}
}
The masterItemList is popluted with all the items at initialization.
My ItemsViewController uses the itemList to populate the cells.
The problem is that itemList is empty when the table view appears, so something not working with this method.
Any ideas on how to get this to work?