How do I prevent unfilled UITextFields from showing up on a randomized count? Xcode - xcode

I am working on an app in which there are five UITextFields in one view controller, the user can fill the text fields they want and when they press a UIButton they'll get a randomized answer on a second view controller via a UILabel.
I got it to work so far, but let's say the user only fills the first two UITextFields and the random answer they get is from a blank, unfilled UITextField.
My question is: how do I make work so that the unfilled UITextFields are not part of the random count? Is this possible?
Here's the code:
FifthViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.choice1.delegate = self;
self.choice2.delegate = self;
self.choice3.delegate = self;
self.choice4.delegate = self;
self.choice5.delegate = self;
}
- (IBAction)choicebutton:(id)sender {
SixthViewController *SVC = [self.storyboard instantiateViewControllerWithIdentifier:#"SixthViewController"];
SVC.stringFromChoice1 = self.choice1.text;
SVC.stringFromChoice2 = self.choice2.text;
SVC.stringFromChoice3 = self.choice3.text;
SVC.stringFromChoice4 = self.choice4.text;
SVC.stringFromChoice5 = self.choice5.text;
[self presentViewController:SVC animated:YES completion:nil];
}
SixthViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.choiceAnswers = #[self.stringFromChoice1,
self.stringFromChoice2,
self.stringFromChoice3,
self.stringFromChoice4,
self.stringFromChoice5];
int index = arc4random() % [self.choiceAnswers count];
self.choiceanswer.text = self.choiceAnswers[index];
}
Thanks!

SixthViewController
You can check and see if a string is empty before adding it to self.choiceAnswers:
if(![self.stringFromChoice1 isEqualToString#""]);
{
[self.choiceAnswers addObject:self.stringFromChoice1];
}
Make sure that you are using an NSMutable array for self.choiceAnswers.

Related

xcode Converting UITableView to UICollectionView (no valid cell)

EDIT: I should specify that this only happens when I attempt to use the UICollectionViewFlowLayout, not when I try to use a custom view. But either way nothing ever shows up on the CollectionView though it was working just fine before I converted from a TableView.)
So I've been trying to convert a UITableView that I had into a UICollectionView. So far so good. But when I try to run the app it gives me the error:
'the collection view's data source did not return a valid cell from -collectionView:cellForItemAtIndexPath: for index path {length = 2, path = 0 - 0}'
I checked all the similar questions and answers here... so in my viewDidLoad I have (tableView is actually a UICollectionView):
UINib * placeCell = [UINib nibWithNibName:#"Shops" bundle:nil];
[self.tableView registerNib:placeCell
forCellWithReuseIdentifier:CellIdentifier];
#pragma mark - UICollectionViewDataSource
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UICollectionView *)tableView numberOfItemsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [_entries count];
//return 5;
}
- (void)tableView:(UICollectionView *)tableView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.item == [_entries count]-1 && page > 1) {
NSLog(#"load more");
//add footer view loading
if (c_page == page) {
// _tableView.tableFooterView = nil;
}
else
{
c_page++;
[self loadPlace:c_page];
}
}
}
- (UICollectionViewCell *)tableView:(UICollectionView *)tableView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
PlaceCell *cell = (PlaceCell *)[tableView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
UINib * placeCell = [UINib nibWithNibName:#"Shops" bundle:nil];
//cell = [cellLoader instantiateWithOwner:self options:nil];
NSArray *topLevelItems = [placeCell instantiateWithOwner:self options:nil];
cell = [topLevelItems objectAtIndex:0];
Place *p = [_entries objectAtIndex:indexPath.row];
cell.placeName.text = p.PName;
NSLog (#"p:%#", p.PName")
cell.placeImg.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:p.PImage]]];
return cell;
}
I went into the xib of the UICollectionViewCell (PlaceCell) and made sure that "Cell" was the reuseidentifier. And I made sure that the datasource and delegate were connected to file's owner in the collectionView.
I also noticed that when I use a custom layout instead of the flow layout (like this one: https://github.com/ShadoFlameX/PhotoCollectionView/blob/master/CollectionViewTutorial/BHPhotoAlbumLayout.m ) it doesn't give me that error... but my collectionview still isn't populated.
So I'm wondering if there's some sort of log I can run or something I can do to figure out what's going wrong. Because I've tried all the solutions I've seen and it hasn't gotten me anywhere.
When you make a cell in a xib file you should register the xib, not the class. Also, when you register either the class or xib (or make the cell in the storyboard), you don't need an if (cell==nil) clause because your cell will never be nil when you dequeue it with dequeueReusableCellWithReuseIdentifier:forIndexPath:. You should delete that clause.
So the problem is: "Switched from UITableView to UICollectionView and no valid cell is being returned." It is really a two part answer. The crux of which is every instance of UITableView...
_tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 50, self.view.bounds.size.width, self.view.bounds.size.height-50)];
...you want to turn into "CollectionView"
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 50, self.view.bounds.size.width, self.view.bounds.size.height-50)];
Everything that's a "row":
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
...you'll want to turn into an "item."
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
Ultimately I had to delete the following section entirely:
UINib * placeCell = [UINib nibWithNibName:#"Shops" bundle:nil];
//cell = [cellLoader instantiateWithOwner:self options:nil];
NSArray *topLevelItems = [placeCell instantiateWithOwner:self options:nil];
cell = [topLevelItems objectAtIndex:0];
My best guess is that the Nib was being loaded twice and that Xcode was complaining that the data wasn't being loaded by the original. So getting rid of that second entry got my cells loaded and populated with data. Hope this helps someone.

Translucent subviews of NSTableView flash when adding/inserting rows

I have a view based NSOutlineView in which the rows contains subviews which have an alpha value of less than 1.
When new rows are inserted or deleted (when the user expands or collapses a row) all of these sub views flash as they seem to temporarily be redrawn with an alpha value of 1.
Does anyone know how to stop this phenomenon ?
I've been looking at this problem four hours, and as so often happens as soon as I post the question here I work out the answer for myself.
Setting up the translucent layers like this solve the issue:
- (void)setup {
// This stops the strange flashing effect when collapsing/expanding rows
self.wantsLayer = YES;
[self.layer setShouldRasterize:YES];
}
- (instancetype)init
{
self = [super init];
if (self) {
[self setup];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
[self setup];
}
return self;
}

Nested NSCollection View

I am trying to create a nested collection view. First I did for one level.
Created a data model class with String header. In app delegate created an array sectionTitle. Now in the nib, I added collection view & array controller and did all the bindings following this guide. Next in awakeFromNib I populated some random data
- (void)awakeFromNib {
int idx = 0;
NSMutableArray *sectionTitle = [[NSMutableArray alloc] init];
while (idx < 1) {
HeaderModel *header = [[HeaderModel alloc] init];
[header setHeader:[NSString stringWithFormat:#"Section %d", idx]];
[sectionTitle addObject:header];
idx++;
}
[self setHeaderData:sectionTitle];
}
Running it will give me 4 sections. I want to achieve similar layout as this. Section title, under it another collection of items. The answer given there only hints at using Nested collection view.
So I added another collection view in the first view prototype. Then I followed the same approach what I did for the first view(with different data model and array).
- (void)awakeFromNib {
int idx = 0;
NSMutableArray *sectionTitle = [[NSMutableArray alloc] init];
NSMutableArray *groupData = [[NSMutableArray alloc] init];
while (idx < 1) {
HeaderModel *header = [[HeaderModel alloc] init];
DataModel *name = [[DataModel alloc] init];
[header setHeader:[NSString stringWithFormat:#"Section %d", idx]];
[name setName:[NSString stringWithFormat:#"Name %d", idx]];
[sectionTitle addObject:header];
[groupData addObject:name];
idx++;
}
[self setHeaderData:sectionTitle];
[self setData:groupData]; //NSCollectionView item prototype must not be nil.
}
But now I get the error NSCollectionView item prototype must not be nil.
How do I resolve this ?
I have just answered a similar question here
But somehow by inserting the second NSCollectionView with I.B, you get a corrupted prototype for your inner NSCollectionViewItem. Simply try to extract each associated NSView into its own .xib

How to add action to a barbuttonitem in a navcontroller that was created programmatically within tabcontroller

I attempted to add the barbuttonitem into the xcode proj and finally got it to show up using the view controller and putting the code in the view did load section but I cannot connect the action... I have always used interface builder and IBOutlets but that is not an option as this navigation controller had to be programmatically put in to have the tab bar controller work
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//add navbar buttons progamatically b/c nothing to use in xibs...
UIBarButtonItem * popbutt = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:#selector(apopbuttonPressed:)];
UINavigationItem * navigItem = [[UINavigationItem alloc]initWithTitle:#"Scribbler"];
navigItem.rightBarButtonItem = popbutt;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
This is my first attempt at putting actions together without using IBOutlet and interface builder so I'm sure it looks pretty bad the goal is to use FPPopover and have the nav bar button item display a popover when pressed
-(void)apopbuttonPressed
{
//the controller we want to present as popover
ScribblePopoverViewController * controller = [[ScribblePopoverViewController alloc] initWithStyle:UITableViewStylePlain];
controller.delegate = self;
apop = [[FPPopoverController alloc] initWithViewController:controller];
//apop.arrowDirection = FPPopoverArrowDirectionAny;
apop.tint = FPPopoverDefaultTint;
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
apop.contentSize = CGSizeMake(300, 500);
}
else {
apop.contentSize = CGSizeMake(200, 300);
}
apop.arrowDirection = FPPopoverArrowDirectionAny;
//sender is the UIButton view
// idk [apop presentPopoverFromView:];
}
you set the selector to "apopbuttonPressed:" <- the ending : says it expects a parameter
your method instead is "apopbuttonPressed" without any parameter.
So try
action:#selector(apopbuttonPressed)
or change your method to
apopbuttonPressed:(id) sender
EDIT: Here is a working code snippet:
this is my code and it works fine:
- (void)viewDidLoad {
[super viewDidLoad];
UIBarButtonItem * popbutt = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:#selector(apopbuttonPressed:)];
self.navigationItem.rightBarButtonItem = popbutt;
}
- (void) apopbuttonPressed:(id) sender
{
NSLog(#"pressed");
}

ipad: predictive search in a popover

I want to implement this
1) when user start typing in a textfield a popOver flashes and shows the list of items in a table view in the popover as per the string entered in textfield.
2) Moreover this data should be refreshed with every new letter entered.
kind of predictive search.
Please help me with this and suggest possible ways to implement this.
UISearchDisplayController does most of the heavy lifting for you.
Place a UISearchBar (not a UITextField) in your view, and wire up a UISearchDisplayController to it.
// ProductViewController.h
#property IBOutlet UISearchBar *searchBar;
#property ProductSearchController *searchController;
// ProductViewController.m
- (void) viewDidLoad
{
[super viewDidLoad];
searchBar.placeholder = #"Search products";
searchBar.showsCancelButton = YES;
self.searchController = [[[ProductSearchController alloc]
initWithSearchBar:searchBar
contentsController:self] autorelease];
}
I usually subclass UISearchDisplayController and have it be it's own delegate, searchResultsDataSource and searchResultsDelegate. The latter two manage the result table in the normal manner.
// ProductSearchController.h
#interface ProductSearchController : UISearchDisplayController
<UISearchDisplayDelegate, UITableViewDelegate, UITableViewDataSource>
// ProductSearchController.m
- (id)initWithSearchBar:(UISearchBar *)searchBar
contentsController:(UIViewController *)viewController
{
self = [super initWithSearchBar:searchBar contentsController:viewController];
self.contents = [[NSMutableArray new] autorelease];
self.delegate = self;
self.searchResultsDataSource = self;
self.searchResultsDelegate = self;
return self;
}
Each keypress in the searchbar calls searchDisplayController:shouldReloadTableForSearchString:. A quick search can be implemented directly here.
- (BOOL) searchDisplayController:(UISearchDisplayController*)controller
shouldReloadTableForSearchString:(NSString*)searchString
{
// perform search and update self.contents (on main thread)
return YES;
}
If your search might take some time, do it in the background with NSOperationQueue. In my example, ProductSearchOperation will call showSearchResult: when and if it completes.
// ProductSearchController.h
#property INSOperationQueue *searchQueue;
// ProductSearchController.m
- (BOOL) searchDisplayController:(UISearchDisplayController*)controller
shouldReloadTableForSearchString:(NSString*)searchString
{
if (!searchQueue) {
self.searchQueue = [[NSOperationQueue new] autorelease];
searchQueue.maxConcurrentOperationCount = 1;
}
[searchQueue cancelAllOperations];
NSInvocationOperation *op = [[[ProductSearchOperation alloc]
initWithController:self
searchTerm:searchString] autorelease];
[searchQueue addOperation:op];
return NO;
}
- (void) showSearchResult:(NSMutableArray*)result
{
self.contents = result;
[self.searchResultsTableView
performSelectorOnMainThread:#selector(reloadData)
withObject:nil waitUntilDone:NO];
}
It sounds like you have a pretty good idea of an implementation already. My suggestion would be to present a UITableView in a popover with the search bar at the top, then simply drive the table view's data source using the search term and call reloadData on the table view every time the user types into the box.

Resources