Passing NSComboBox value that is inside a NSAlert Sheet - objective-c

I have a NSAlert Sheet that has a NSComboBox inside. How can i pass the combo box value when the user has pressed a button of the NSAlert?
code:
NSComboBox* comboBox = [[NSComboBox alloc] initWithFrame:NSMakeRect(0, 0, 150, 26)];
[comboBox setTitleWithMnemonic:#"2"];
for (int i=2; i<[array count]+1; i++){
[comboBox addItemWithObjectValue:[NSString stringWithFormat:#"%i", i]];
}
[comboBox setEditable:NO];
NSAlert *alert = [[NSAlert alloc] init];
[alert addButtonWithTitle:#"Okay"];
[alert addButtonWithTitle:#"Cancel"];
[alert setMessageText:#"Choose a number"];
[alert setAccessoryView:comboBox];
[alert beginSheetModalForWindow:_window modalDelegate:self didEndSelector:#selector(alertToChooseX:returnCode:contextInfo:) contextInfo:nil];
- (void)alertToChooseX:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo {
if (returnCode == NSAlertFirstButtonReturn) {
NSLog(#"Pressed Okay");
}
}

Describe comboBox in Your header file and after pushed button "Okay" take it's value like this:
in .h
NSComboBox *comboBox;
in .m
comboBox = [[NSComboBox alloc] initWithFrame:NSMakeRect(0, 0, 150, 26)];
[comboBox setTitleWithMnemonic:#"2"];
.... // Your all code goes here
- (void)alertToChooseX:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo {
if (returnCode == NSAlertFirstButtonReturn) {
NSLog(#"Pressed Okay");
NSLog(#"Selected ComboBox's String Value: %#", [comboBox stringValue]);
NSLog(#"Selected ComboBox's Object Value: %#", [comboBox objectValueOfSelectedItem]);
NSLog(#"Selected ComboBox's Item Index: %ld", [comboBox indexOfSelectedItem]);
}
}
Note: Don't forget to release comboBox because it's allocating memory.

Related

NSAlert Input Box, Validating NSTextField

I've run into a couple of topics that discuss an input box using NSAlert like the following.
- (NSString *)input: (NSString *)prompt defaultValue: (NSString *)defaultValue {
NSAlert *alert = [NSAlert alertWithMessageText: prompt
defaultButton:#"OK"
alternateButton:#"Cancel"
otherButton:nil
informativeTextWithFormat:#""];
NSTextField *input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 200, 24)];
[input setStringValue:defaultValue];
[alert setAccessoryView:input];
NSInteger button = [alert runModal];
if (button == NSAlertDefaultReturn) {
[input validateEditing];
return [input stringValue];
} else if (button == NSAlertAlternateReturn) {
return nil;
} else {
return nil;
}
}
So you can insert a textbox just like you do with AlertView in iOS. But how can you validate the text field value to enable and disable the default button? iOS has (BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView to let you validate the input.
Thank you.
set
input.delegate=self;
and then implement the following methods
(void)controlTextDidChange:(NSNotification *)notification
(void)controlTextDidEndEditing:(NSNotification *)notification
you can validate here

I Need an Action to Change my NSArray by pressing a button in UIAlertView

I have a UITableView set up programatically, and it is populated with all the names of the states. When you click on one of the cells, for ex. ALABAMA, a UIAlertView will appear With the title being that of the state you just clicked on (ALABAMA) and a number that correlates to that state, which is in another NSMutable Array. Every state has a different number to correlate with it.
This number is actually a placeholder text in the UIAlert, and the purpose of the alert is so that you can input a number in the text field, and when you hit the CHANGE button, the number that was in the placeholder text (from the Array) will be changed with the number that the user imputed; permanently. All is good until I hit change, and then I get a SIGABRT error, and in output it reads:
2013-02-21 20:57:33.750 final[10046:11303] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM replaceObjectAtIndex:withObject:]: object cannot be nil'
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:[NSString stringWithFormat:#"%#", [states objectAtIndex:indexPath.row]]
message:[NSString stringWithFormat:#"%#", [tax objectAtIndex:53]]
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Change", nil];
UITextField *myTextField =[[UITextField alloc] initWithFrame:CGRectMake(42, 50, 200, 25)];
CGAffineTransform myTransform =CGAffineTransformMakeTranslation(0, 0);
[alertView setTransform:myTransform];
[myTextField setBackgroundColor:[UIColor clearColor]];
[alertView addSubview:myTextField];
myTextField.placeholder = [NSString stringWithFormat:#"%#", [tax objectAtIndex:indexPath.row]];
myTextField.borderStyle = UITextBorderStyleNone;
myTextField.returnKeyType = UIReturnKeyDone;
myTextField.textColor = [UIColor grayColor];
myTextField.keyboardType = UIKeyboardTypeNumbersAndPunctuation;
myTextField.textAlignment = UITextAlignmentCenter;
myTextField.delegate = self;
[alertView show];
[alertView release];
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 1) {
NSString *theTaxer = [myTextField text];
[tax replaceObjectAtIndex:1 withObject:theTaxer];
}
}
At the point when alertView:clickedBUttonAtIndex is called myTextField is no longer defined since myTextField isn't defined as a class ivar you can only reference it in the function you created it in. If you want to reference myTextField elsewhere in your class (in the alertView callback for instance) make it a class iVar.
Try this,
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:[NSString stringWithFormat:#"%#", [states objectAtIndex:indexPath.row]]
message:[NSString stringWithFormat:#"%#", [tax objectAtIndex:53]]
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Change", nil];
alertView.tag =indexPath.row;
UITextField *myTextField =[[UITextField alloc] initWithFrame:CGRectMake(42, 50, 200, 25)];
[myTextField setTag:99];
CGAffineTransform myTransform =CGAffineTransformMakeTranslation(0, 0);
[alertView setTransform:myTransform];
[myTextField setBackgroundColor:[UIColor clearColor]];
[alertView addSubview:myTextField];
myTextField.placeholder = [NSString stringWithFormat:#"%#", [tax objectAtIndex:indexPath.row]];
myTextField.borderStyle = UITextBorderStyleNone;
myTextField.returnKeyType = UIReturnKeyDone;
myTextField.textColor = [UIColor grayColor];
myTextField.keyboardType = UIKeyboardTypeNumbersAndPunctuation;
myTextField.textAlignment = UITextAlignmentCenter;
myTextField.delegate = self;
[alertView show];
[alertView release];
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 1) {
UITextField * myTextField = (UITextField *)[alertView viewWithTag:99];
NSString *theTaxer = [myTextField text];
[tax replaceObjectAtIndex:1 withObject:theTaxer];
}
}
Shizam is right, I think if you want get the reference of the textview, just give a tag to the textview when you create the alertview like this: myTextField.tag = 111;
and then in the alertView delegate method:
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 1) {
UITextField *textField = [alertView viewWithTag:111];
NSString *theTaxer = [textField text];
[tax replaceObjectAtIndex:1 withObject:theTaxer];
}
}

My picker is not actually selecting values?

So I have a picker that pops up instead of the keyboard, however it does not change values when you scroll to different points on the picker. I test this by having an alert show what age was selected, and it never changes from the first option. I would think the alert is broken, but the blue selector outline over the currently selected option in the picker is not showing up either. Here is the code for both the picker and the alert:
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *array = [[NSArray alloc] initWithObjects:#"18-29",#"30-39",#"40-49",#"50-59",#"60+",nil];
self.pickerData = array;
}
-(IBAction)UITextFieldEditingDidBegin
{
UIPickerView *picker = [[UIPickerView alloc]
initWithFrame:CGRectMake(0, 244, 320, 270)];
picker.delegate = self;
picker.dataSource = self;
[self.view addSubview:picker];
[picker release];
}
-(IBAction)donePressed
{
NSInteger row = [agePicker selectedRowInComponent:0];
NSString *selected = [pickerData objectAtIndex:row];
NSString *title = [[NSString alloc] initWithFormat:
#"You selected %#!", selected];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title
message : #"Thank you for choosing."
delegate:nil
cancelButtonTitle :#"Okay!"
otherButtonTitles :nil];
[alert show];
[agePicker resignFirstResponder];
}
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
-(NSInteger)pickerView:(UIPickerView *)pickerView
numberOfRowsInComponent:(NSInteger)component
{
return [pickerData count];
}
-(NSString *)pickerView:(UIPickerView *)pickerView
titleForRow:(NSInteger)row
forComponent:(NSInteger)component
{
return[pickerData objectAtIndex:row];
}
Edit,
to help dismiss your picker,
make it an instance var, declare your picker in the interface,
MyClass.h
#interface MyClass:UIViewController <UIPickerViewDelegate, UIPickerViewDataSource>{
UIPickerView *picker
}
MyClass.m
#interface MyClass()
property (nonatomic, retain) *selectedVal; //make it a NSString
#end
-(IBAction)UITextFieldEditingDidBegin
{
picker = [[UIPickerView alloc]
initWithFrame:CGRectMake(0, 244, 320, 270)];
picker.delegate = self;
picker.dataSource = self;
[self.view addSubview:picker];
//[picker release]; //Place your picker release in the dealloc method
}
You have to implement the delegate for the picker,
- (void)pickerView:(UIPickerView *)thePickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
self.selectedVal = [pickerData objectAtIndex:row]
NSLog(#"Selected option: %#. ", self.selectedVal );
}
Then on your done button, you have the selected val in your property for use
-(IBAction)donePressed
{
NSString *title = [[NSString alloc] initWithFormat:
#"You selected %#!", self.selectedVal];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title
message : #"Thank you for choosing."
delegate:nil
cancelButtonTitle :#"Okay!"
otherButtonTitles :nil];
[alert show];
[alert release]; //I noticed you release the picker, so not using ARC, so release alert!!
[picker resignFirstResponder];
//after done, remove the picker from the view
[picker removeFromSuperview];
}

iOS: Image Will Not Delete From Array

I'm working on an app that behaves like a photo gallery, and I'm implementing the option to have the user delete photos from their gallery. To accomplish this, I decided to place an invisible button over each picture. When the user hits an "Edit" button, the hidden delete buttons over each picture become active. I'm using the same IBOutlet over each of the hidden buttons for simplicity, and I've tagged each button appropriately in Interface Builder. When the user taps the button over the picture, an alert view appears asking if they really want to delete it. If they click yes, I call removeObjectAtIndex. Here is the code I'm using:
- (IBAction)deleteButtonPressed:(id)sender {
NSLog(#"Sender is %#", sender);
UIAlertView *deleteAlertView = [[UIAlertView alloc] initWithTitle:#"Delete"
message:#"Are you sure you want to delete this photo?"
delegate:self
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes", nil];
[deleteAlertView show];
int imageIndex = ((UIButton *)sender).tag;
deleteAlertView.tag = imageIndex;
}
- (void)alertView: (UIAlertView *) alertView
clickedButtonAtIndex: (NSInteger) buttonIndex
{
if (buttonIndex != [alertView cancelButtonIndex]) {
NSLog(#"User Clicked Yes.");
[self.array removeObjectAtIndex: alertView.tag];
}
[self.user setObject:array forKey:#"images"];
}
The issue here is that when I click "Yes" in the alert view, nothing happens. However, if I tap on the image and click "Yes" a second time, the app crashes, and the debug states:
Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFArray removeObjectAtIndex:]: index (0) beyond bounds (0)' So, I'm not sure where to go from here, I'm still very new to programming and everything looks correct to me. Any help is much appreciated, thanks!
Here is how I add them into the array:
////start of saving////
- (void)viewWillAppear:(BOOL)animated
{
self.user = [NSUserDefaults standardUserDefaults];
self.array = [[self.user objectForKey:#"images"]mutableCopy];
while(self.array == nil)
{
[self.user setObject:[NSMutableArray arrayWithObject:#""] forKey:#"images"];
self.array = [[self.user objectForKey:#"images"]mutableCopy];
NSLog(#"%#",#"attempting to create an array to store the images in");
}
}
- (void)applicationDidEnterBackground:(UIApplication*)application {
NSLog(#"Image on didenterbackground: %#", imageView);
self.array = [NSMutableArray arrayWithObject:[NSData dataWithData:UIImagePNGRepresentation(imageView.image)]];
[self.array addObject:[NSData dataWithData:UIImagePNGRepresentation(imageView2.image)]];
[self.array addObject:[NSData dataWithData:UIImagePNGRepresentation(imageView3.image)]];
[self.array addObject:[NSData dataWithData:UIImagePNGRepresentation(imageView4.image)]];
[self.array addObject:[NSData dataWithData:UIImagePNGRepresentation(imageView5.image)]];
[self.user setObject:self.array forKey:#"images"];
[user synchronize];
}
- (void)viewDidLoad
{
self.user = [NSUserDefaults standardUserDefaults];
NSLog(#"It is %#", self.user);
self.array = [[self.user objectForKey:#"images"]mutableCopy];
imageView.image = [[UIImage alloc] initWithData:[self.array objectAtIndex:0]];
imageView2.image = [[UIImage alloc] initWithData:[self.array objectAtIndex:1]];
imageView3.image = [[UIImage alloc] initWithData:[self.array objectAtIndex:2]];
imageView4.image = [[UIImage alloc] initWithData:[self.array objectAtIndex:3]];
imageView5.image = [[UIImage alloc] initWithData:[self.array objectAtIndex:4]];
imageView6.image = [[UIImage alloc] initWithData:[self.array objectAtIndex:5]];
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(applicationDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:app];
backToGalleryButton.hidden = YES;
tapToDeleteLabel.hidden = YES;
deleteButton1.hidden = YES;
[super viewDidLoad];
}
- (void)viewDidUnload
{
self.user = nil;
}
////end of saving
///// shows the hidden and invisible "delete" button over each photo.
- (IBAction)editButtonPressed:(id)sender {
grabButton.hidden = YES;
editButton.hidden = YES;
backToGalleryButton.hidden = NO;
tapToDeleteLabel.hidden = NO;
deleteButton1.hidden = NO;
}
- (IBAction)deleteButtonPressed:(id)sender {
NSLog(#"Sender is %#", sender);
UIAlertView *deleteAlertView = [[UIAlertView alloc] initWithTitle:#"Delete"
message:#"Are you sure you want to delete this photo?"
delegate:self
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes", nil];
[deleteAlertView show];
int imageIndex = ((UIButton *)sender).tag;
deleteAlertView.tag = imageIndex;
}
- (void)alertView: (UIAlertView *) alertView
clickedButtonAtIndex: (NSInteger) buttonIndex
{
if (buttonIndex != [alertView cancelButtonIndex]) {
NSLog(#"User Clicked Yes.");
NSLog(#"Array: %#, index: %d", self.array, alertView.tag);
[self.array removeObjectAtIndex: alertView.tag];
}
[self.user setObject:array forKey:#"images"];
}
#end
EDIT: This is the code I use to put the objects into the UIImageView from the users camera roll:
- (IBAction)grabImage {
self.imgPicker = [[UIImagePickerController alloc] init];
self.imgPicker.delegate = self;
self.imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
_popover = [[UIPopoverController alloc] initWithContentViewController:imgPicker];
[_popover presentPopoverFromRect:self.imageView.bounds inView:self.imageView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
else {
[self presentModalViewController:imgPicker animated:YES];
}
[self.imgPicker resignFirstResponder];
}
// Sets the image in the UIImageView
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)img editingInfo:(NSDictionary *)editInfo {
if (imageView.image == nil) {
imageView.image = img;
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
if (imageView2.image == nil) {
imageView2.image = img;
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
if (imageView3.image == nil) {
imageView3.image = img;
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
if (imageView4.image == nil) {
imageView4.image = img;
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
}
When I added NSLog(#"Array: %#, index: %d", self.array, alertView.tag); just before removeAtIndex the console says 2012-04-03 18:39:39.066 AppName[1631:f803] Array: (null), index: 0. Could that be the cause? I'm not sure why it would be, I think the code looks fine.
Removing the image from the array is not the only step you have to take. Your code is correct for removing the image from the array, which is why you get image out of bounds the second time, but you also need to remove the image from the UI so the user can no longer delete an image that is not there.
There are many oddities with this code but I think the problem is that you are not calling super on your viewwillappear and viewdidload functions. I would get rid of your viewWillAppear method as it serves no purpose.

-initWithContentsOfFile: for an NSMutableArray

I stored images in an NSMutableArray, and now I'm trying to get them to show up in viewDidLoad. I tried calling initWithContentsOfFile, but that doesn't seem to work. This is how the code looks:
imageView.image = [[UIImage alloc] initWithContentsOfFile:[self.array objectAtIndex:0]];
I'm not sure what I should use instead of initWithContentsOfFile to have the saved images load, I'm not even sure if I can save images in a plist through user defaults. I've been researching it for awhile now to no avail. Any help is much appreciated, thanks!
EDIT: Here is additional code:
- (IBAction)grabImage {
self.imgPicker = [[UIImagePickerController alloc] init];
self.imgPicker.delegate = self;
self.imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
_popover = [[UIPopoverController alloc] initWithContentViewController:imgPicker];
[_popover presentPopoverFromRect:self.imageView.bounds inView:self.imageView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
else {
[self presentModalViewController:imgPicker animated:YES];
}
[self.imgPicker resignFirstResponder];
}
// Sets the image in the UIImageView
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)img editingInfo:(NSDictionary *)editInfo {
if (imageView.image == nil) {
imageView.image = img;
[self.array addObject:imageView.image];
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
if (imageView2.image == nil) {
imageView2.image = img;
NSLog(#"The image is a %#", imageView);
[self.array addObject:imageView2.image];
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
if (imageView3.image == nil) {
imageView3.image = img;
[self.array addObject:imageView3.image];
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
}
- (void)applicationDidEnterBackground:(UIApplication*)application {
NSLog(#"Image on didenterbackground: %#", imageView);
[self.array addObject:imageView.image];
[self.array addObject:imageView2.image];
[self.array addObject:imageView3.image];
[self.user setObject:self.array forKey:#"images"];
[user synchronize];
}
- (void)viewDidLoad
{
self.user = [NSUserDefaults standardUserDefaults];
NSLog(#"It is %#", self.user);
self.array = [[self.user objectForKey:#"images"]mutableCopy];
imageView.image = [[UIImage alloc] initWithContentsOfFile:[self.array objectAtIndex:0]];
imageView2.image = [[UIImage alloc] initWithContentsOfFile:[self.array objectAtIndex:1]];
imageView3.image = [[UIImage alloc] initWithContentsOfFile:[self.array objectAtIndex:2]];
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(applicationDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:app];
backToGalleryButton.hidden = YES;
tapToDeleteLabel.hidden = YES;
deleteButton1.hidden = YES;
[super viewDidLoad];
}
EDIT: This is how I'm tagging the images and deleting them based upon their tags:
- (IBAction)deleteButtonPressed:(id)sender {
NSLog(#"Sender is %#", sender);
UIAlertView *deleteAlertView = [[UIAlertView alloc] initWithTitle:#"Delete"
message:#"Are you sure you want to delete this photo?"
delegate:self
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes", nil];
[deleteAlertView show];
int imageIndex = ((UIButton *)sender).tag;
deleteAlertView.tag = imageIndex;
}
- (UIImageView *)viewForTag:(NSInteger)tag {
UIImageView *found = nil;
for (UIImageView *view in self.array) {
if (tag == view.tag) {
found = view;
break;
}
}
return found;
}
- (void)alertView: (UIAlertView *) alertView
clickedButtonAtIndex: (NSInteger) buttonIndex
{
if (buttonIndex != [alertView cancelButtonIndex]) {
NSLog(#"User Clicked Yes. Deleting index %d of %d", alertView.tag, [array count]);
NSLog(#"The tag is %i", alertView.tag);
UIImageView *view = [self viewForTag:alertView.tag];
if (view) {
[self.array removeObject:view];
}
NSLog(#"After deleting item, array count = %d", [array count]);
NSLog(#"Returned view is :%#, in view: %#", [self.view viewWithTag:alertView.tag], self.view);
((UIImageView *)[self.view viewWithTag:alertView.tag]).image =nil;
}
[self.user setObject:self.array forKey:#"images"];
}
The problem is that you can't store images in a property list, which is what you're trying to do when you save it in the user defaults. You need to use an archiver to convert the image to an NSData object which you can store.
It looks like you're not passing a valid image path to the initializer method. Make sure the path is correct, and that it includes the image extension.
Really, though, you shouldn't be calling initWithContentsOfFile: in this case, because UIImageView's image property retains the image when you set it. That will usually lead to a memory leak (unless you're using automatic reference counting). Use one of the static initializers instead, such as imageNamed:, which has the added bonuses of using the system cache and also automatically loading the correct version of the image based on the characteristics of the device (for instance, it will load a higher resolution variant of the image if the device has a retina display).