iOS 7 UITextView's native links don't cancel touch - ios7

I think I've encountered a bug in UITextView in iOS 7, but I haven't been able to find any reference to it or discussion, so trying to confirm here that I'm not missing something:
The Bug
I have a UITextView setup as follows:
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(20, 100, 280, 140)];
textView.editable = NO;
textView.dataDetectorTypes = UIDataDetectorTypeLink;
textView.backgroundColor = [UIColor lightGrayColor];
textView.delegate = self;
textView.text = [NSString stringWithFormat:#"This is a UITextView in a UIViewController. It has editable %d, selectable %d, dataDectorTypes %d (UIDataDetectorTypeLink), and a link! http://www.google.com.\n\nIf you click the link, it works normally. If you press, then drag your finger away to cancel the touch, the highlight goes away but the action still fires. Shouldn't the action not fire?", textView.editable, textView.selectable, textView.dataDetectorTypes];
[self.view addSubview:textView];
The textview text contains a link, which if you click works as expected: it calls back to the delegate, which just pops up an alert:
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"You clicked the link!" message:#"You clicked the link. Maybe you tried to move away to cancel the touch, but you clicked it anyway." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
return NO;
}
The problem is if you press the link, then try to drag away to cancel the touch: the link's highlight state goes away but the delegate fires as soon as your finger leaves the screen.
I haven't been able to find a way to tell the textview not to fire when it should have cancelled, or to detect that it should have cancelled.
I'm convinced this is a bug because the visual press/cancel state and the action-firing don't match.

Work-around (horrible horrible invasive work-around)
I got around this by subclassing UIApplication to track all screen touches. By holding on to the last touch location, I can, in the delegate, map the location to the link to determine whether or not it should be considered valid:
MyCustomApplication.m
#implementation MyCustomApplication
static CGPoint lastTouchVar;
- (void)sendEvent:(UIEvent *)event {
if (event.type == UIEventTypeTouches) {
lastTouchVar = [((UITouch*)event.allTouches.anyObject) locationInView:[[[UIApplication sharedApplication] delegate] window]];
}
[super sendEvent:event];
}
+ (CGPoint)lastTouch {
return lastTouchVar;
}
#end
(use it in main.m)
int main(int argc, char *argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, #"MyCustomApplication", NSStringFromClass([MyAppDelegate class]));
}
}
And map it...
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange {
CGPoint lastTouchWRTTextView = [[[[UIApplication sharedApplication] delegate] window] convertPoint:[MyCustomApplication lastTouch] toView:textView];
lastTouchWRTTextView.x -= textView.textContainerInset.left;
lastTouchWRTTextView.y -= textView.textContainerInset.top;
if (CGRectContainsPoint(CGRectMake(0, 0, textView.frame.size.width, textView.frame.size.height), lastTouchWRTTextView)) {
int characterIndexForPoint = [textView.textContainer.layoutManager characterIndexForPoint:lastTouchWRTTextView inTextContainer:textView.textContainer fractionOfDistanceBetweenInsertionPoints:nil];
if (NSLocationInRange(characterIndexForPoint, characterRange)) {
// It's a real tap! Do something!
}
}
return NO;
}

Related

what's the difference between self.view.widow and [[UIApplication sharedApplication] keyWindow] in Objective-C

if I do like this
- (void)viewDidLoad {
[super viewDidLoad];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:#"test" delegate:self cancelButtonTitle:#"ok" otherButtonTitles:nil];
[alert show];
}
// Called when a button is clicked. The red view and alert will be automatically dismissed after this call returns
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
[self showView];
}
// after animation ,this will work fine
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
// [self showView];
}
- (void)showView {
// Called when a button is clicked. The view will be automatically dismissed after this call returns
UIView *view = [[UIView alloc] init];
view.frame = CGRectMake(0, 0, 200, 200);
view.backgroundColor = [UIColor redColor];
view.center = CGPointMake([UIScreen mainScreen].bounds.size.width/2.0f, [UIScreen mainScreen].bounds.size.height/2.0f);
// [self.view.window addSubview:view]; //when i use this ,both of the two delegate methods works fine
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
[window addSubview:view];
}
Then the red view and alert will be automatically dismissed after alertView:clickedButtonAtIndex: call returns
who can show me the reason?
what's the difference between self.view.widow and [[UIApplication sharedApplication] keyWindow] in Objective-C
Your question is essentially addressed here:
diffrence between [[[[UIApplication sharedApplication] delegate] window] and [[UIApplication sharedApplication].keyWindow?
To tie it back to your question, the UIAlertView gets presented in a system window, and it is this window that is the keyWindow while your alert is being shown. When the alert is dismissed, that window disappears, hence why your view disappears.
Assuming that self.view is a subview of the app's window (almost always the case), your view continues to display because the window itself continues to be displayed after the alert is dismissed.

Dynamic textView resize broken after update to iOS 7.1

I have a tableview that requires a subview that's used to add content. The subview contains a UITextView that's used to enter text. Prior to 7.1 The following would happen:
The subview is glued to the bottom of the tableview via scrollViewDidScroll
When activated, the keyboard would show, the view animates up with the keyboard
When text is typed in, the textView would expand upwards if required, with the bottom of the textView remaining in place.
NOW after 7.1, the following behavior takes place:
The subview animates upwards with the keyboard fine
If the text forces a new line, instead of expanding, textViewDidEndEditing get's triggered and the keyboard dismisses.
No further editing is allowed in the textview, any edits makes the keyboard immediately dismiss.
Any suggestions on what changed with 7.1 that would make existing, working code break? Here is all the relevant code. I'll be happy to provide any additional details. I've been at this a while now and it's driving me mental.
tableViewController.m - The code that adds in the subview. The subview has it's own xib. The xib was created in IB. I stripped out the parts that pertain to other components.
- (void)viewDidLoad {
//Setup contentBar
if (self.contentBar == nil) {
//Add subView to View
NSArray *subviewArray = [[NSArray alloc] init];
subviewArray = [[NSBundle mainBundle] loadNibNamed:contentIdentifier owner:self options:nil];
self.contentBar = [subviewArray objectAtIndex:0];
[self.view addSubview:self.contentBar];
//Setup textView
UITextView *addContentTextView = (UITextView *)[self.contentBar viewWithTag:2];
addContentTextView.text = [NSString stringWithFormat:#"text (optional)"];
addContentTextView.delegate = self;
}
}
My textView delegates
#pragma mark - TextView Delegate
- (void)textViewDidEndEditing:(UITextView *)textView{
NSLog(#"textViewDidEndEditing:");
if ([textView.text isEqualToString:#""]) {
textView.text = #"text (optional)";
textView.textColor = [UIColor lightGrayColor]; //optional
}
[textView resignFirstResponder];
}
- (void)textViewDidBeginEditing:(UITextView *)textView {
NSLog(#"textViewDidBeginEditing:");
if ([textView.text isEqualToString:#"text (optional)"]) {
textView.text = #"";
textView.textColor = [UIColor blackColor]; //optional
}
[textView becomeFirstResponder];
}
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
NSString *newText = [textView.text stringByReplacingCharactersInRange:range withString:text];
if ([newText length] > 0 || _image) {
_addContentButton.enabled = YES;
} else {
_addContentButton.enabled = NO;
}
if([text isEqualToString:[text stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]]) {
return YES;
} else {
NSLog(#"return pressed");
[textView resignFirstResponder];
[self addedContent:nil];
}
return YES;
}
- (void)textViewDidChange:(UITextView *)textView
{
NSLog(#"textViewDidChange");
[self sizeTextView];
}
- (void)sizeTextView
{
NSLog(#"sizeTextView");
UIImageView *barImage = (UIImageView *)[self.contentBar viewWithTag:87];
UITextView *textView = (UITextView *)[self.contentBar viewWithTag:2];
CGSize sizeThatShouldFitTheContent = [textView sizeThatFits:textView.frame.size];
CGRect newTextViewFrame = textView.frame;
newTextViewFrame.size.height = sizeThatShouldFitTheContent.height;
CGFloat adjustment = sizeThatShouldFitTheContent.height - textView.frame.size.height;
newTextViewFrame.origin.y = textView.frame.origin.y - adjustment;
textView.frame = newTextViewFrame;
CGRect newImageViewFrame = barImage.frame;
newImageViewFrame.size.height = barImage.frame.size.height + adjustment;
newImageViewFrame.origin.y = barImage.frame.origin.y - adjustment;
barImage.frame = newImageViewFrame;
}
If you want to see anything else, I'll be glad to post it.
I have solved this issue by implementing the following:
Rewrote my tableview controller as a standard ViewController, not a TableViewController
Added a tableview to the ViewController and a separate "contentWrapper" view.
The content wrapper consists of the example shown here: https://github.com/datwelk/RDRStickyKeyboardView
I'm still not sure what in iOS 7.1 caused this issue, but using the RDRStickyKeyboardView works great and solved all of my issues.
I've read that tableviews shouldn't be parents of other views, so this solution also works well for good coding practice.

UIAlertView showing up only after it's dismissed

I've been trying to figure this out for 2 days now, and before anyone posts another stackoverflow question, I've read them all and none of them cover my problem exactly:
I have a CoreData app that updates dynamically. Now during the update I want an UIAlertView to pop up saying that an update is being downloaded.
So here's the important code:
AppDelegate:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[myUpdater checkForUpdatesInContext:self.managedObjectContext];
}
_
Updater Class:
- (void)checkForUpdatesInContext:(NSManagedObjectContext *)myManagedObjectContext
{
[self loadUpdateTime];
NSLog(#"Update start");
NSDate *now = [NSDate dateWithTimeIntervalSinceNow:[[NSTimeZone localTimeZone] secondsFromGMT]];
if ([now timeIntervalSinceDate:updateTime] < UPDATE_TIME_INTERVAL)
{
return;
}
[self showAlertViewWithTitle:#"Update"];
... //updating process
[self.alertView dismissWithClickedButtonIndex:0 animated:YES];
NSLog (#"Update done");
}
- (void) showAlertViewWithTitle:(NSString *)title
{
self.alertView = [[UIAlertView alloc] initWithTitle:title message:#"Daten werden aktualisiert..." delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
... //design the alertView
[self.alertView show];
NSLog (#"AlertView shows");
}
So here is what happens when I run this:
Launch image shows
NSLog "Update starts" fires
NSLog "AlertView shows" fires
Screen dims but no AlertView is shown
Update is running
NSLog "Update done" fires
Launch image goes away and TabBarController shows up
UIAlertView shows up and is dismissed right away and the dimmed screen returns to normal
What I would like to have happen:
Launch image
TabBarController shows up
Screen dims and UIAlertView shows
Update is running
UIAlertView gets dismissed and dimmed screen returns to normal
I know it's something with the UI Thread and the main Thread and stuff.. But I tried every combination it seems but still not the expected result. Please help :)
EDIT:
HighlightsViewController Class:
- (void)viewDidLoad
{
[super viewDidLoad];
self.updater = [[Updater alloc] init];
[updater checkForUpdatesInContext:self.managedObjectContext];
... // other setup stuff nothing worth mentioning
}
Is this the right place to call [super viewDidLoad]? Because it still doesn't work like this, still the update is being done while the Launch Image is showing on the screen. :-(( I'm about to give this one up..
Here you go, in this prototype things work exactly how you want them to.
Header:
#import <UIKit/UIKit.h>
#interface AlertViewProtoViewController : UIViewController
{
}
- (void) showAlertViewWithTitle:(NSString *)title;
- (void) checkForUpdatesInContext;
- (void) update;
- (void)someMethod;
- (void)someOtherMethod;
#end
#import "AlertViewProtoViewController.h"
Class:
#implementation AlertViewProtoViewController
UIAlertView *alertView;
bool updateDone;
UILabel *test;
bool timershizzle;
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor yellowColor];
UILabel *test = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
test.backgroundColor = [UIColor blueColor];
[self.view addSubview:test];
[self performSelector:#selector(checkForUpdatesInContext) withObject:nil afterDelay:0.0];
}
- (void)update
{
//NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; //commented for auto ref counting
NSLog(#"update start");
//your update stuff
NSLog(#"update end");
updateDone = YES;
//[pool release];
}
- (void)checkForUpdatesInContext//:(NSManagedObjectContext *)myManagedObjectContext
{
//[self loadUpdateTime];
NSLog(#"Update start");
NSDate *now = [NSDate dateWithTimeIntervalSinceNow:[[NSTimeZone localTimeZone] secondsFromGMT]];
// if ([now timeIntervalSinceDate:updateTime] < UPDATE_TIME_INTERVAL)
// {
// return;
// }
[self showAlertViewWithTitle:#"Update"];
//[self setManagedObjectContext:myManagedObjectContext];
[self performSelector:#selector(someMethod) withObject:nil afterDelay:0.0];
[self performSelector:#selector(someOtherMethod) withObject:nil afterDelay:0.0];
}
-(void)someOtherMethod
{
while (!updateDone) {
// NSLog(#"waiting...");
}
[alertView dismissWithClickedButtonIndex:0 animated:YES];
NSLog (#"Update done");
self.view.backgroundColor = [UIColor greenColor];
}
-(void)someMethod
{
[self performSelectorInBackground:#selector(update) withObject:nil];
}
- (void) showAlertViewWithTitle:(NSString *)title
{
alertView = [[UIAlertView alloc] initWithTitle:title message:#"Daten werden aktualisiert..." delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
alertView.frame = CGRectMake(100, 100, 200, 200);
alertView.backgroundColor = [UIColor whiteColor];
[self.view addSubview:alertView];
[self.view setNeedsDisplay];
NSLog (#"AlertView shows");
}
#end
You should adjust were needed for your own purposes but it works.
You are starting a background thread and then dismissing the alert immediately. I would suggest that you might use an NSNotification, posted from the background task, and received in whichever controller starts the alert, triggering a method that dismissed the alert.
I find the UIAlertView interface unsuitable for this type of user notice, and prefer to use a semi-transparent overlay view with a UIActivityIndicatorView, plus an informing message for the user.
You are doing a:
- (void)applicationDidBecomeActive:(UIApplication *)application
Isn't it so that the alertview you want to show needs a view to be loaded which isn't active yet at this point? See: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIAlertView_Class/UIAlertView/UIAlertView.html
Similar question? UIAlertView starts to show, screen dims, but it doesn't pop up until it's too late!

Displaying UIAlertViews Sequentially

I have several UIAlertViews that i want to display in a sequential order, and only move on to display the next UIAlertView once the previous one has been dismissed (by user clicking okay).
I know about the didDismissWithButtonIndex delegate and adding a tag, but this doesn't really help too much as there could be upto 3 UIAlertViews invoked and not necessarily in the same order everytime. see code:
if(condition 1){
alert1 = // UIAlertView[[.....
[alert1 show]
}
if(condition 2){
alert2 = // UIAlertView[[.....
[alert2 show]
}
if(condition 3){
alert3 = // UIAlertView[[.....
[alert3 show]
}
The above will just add 3 Alerts on top of each other (depending on how many conditions are met) which is not what I want. I want to be able to only show one at a time and then the next one (if there is one) after the user hits the ok button.
I had the idea of maybe adding the messages to a queue and then processing that queue removing the alert every time an alert is dismissed but i'm not sure how id go about doing that.
Any ideas would be much appreciated.
Thanks
You could easily do it in the UIAlertView delegate method, called once an alert view is dismissed. So, UIAlertViewDelegate defines the following delegate method:
– alertView:didDismissWithButtonIndex:
Implement that method, and make sure your class is the delegate of the UIAlertViews you create. This method is the perfect place to then show the next alert based on the one being dismissed by the user.
If your requirement is "Display up to three alerts, sequentially, but not always in the same order" i'd probably put the alerts in to an array, and then in the delegate method get the next alert out of the array to show. It doesn't have to be any more complex than that really; the key thing is that the delegate method implementation is the best place to show the next alert.
Pseudo Code Example:
Define an array; NSMutableArray * alerts_;
- (void)showAlertSequence {
if ( !alerts_ ) {
alerts_ = [[NSMutableArray alloc] init];
}
[alerts_ addObjects;<My alerts>];
[self showSequencedAlertFrom:nil];
}
- (BOOL)showSequencedAlertFrom:(UIAlertView *)sourceAlertView {
if ( !sourceAlertView ) {
[[alerts_ objectAtIndex:0] show];
}
else {
NSInteger index = [alerts_ indexOfObject:sourceAlertView];
if ( index < [alerts_ count] ) {
[[alerts_ objectAtIndex:index++] show];
}
}
return NO;
}
– alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)index {
// Show the next alert or clean up if we're at the end of the sequence.
if ( ![self showSequencedAlertFrom:alertView] ) {
[alerts_ removeAllObjects];
}
}
As an aside; three sequential alerts will really annoy you users ;)
One thing that I've done is used block based UIAlertViews by adding a category on AlertView.
Here is the .h file
#interface UIAlertView (WithBlocks)
- (id) initWithTitle:(NSString *)title message:(NSString *)message;
- (void) addButtonWithTitle:(NSString *)title andBlock:(void(^)())block;
#end
Here is the .m file
static NSString *BUTTON_BLOCK_KEY = #"alertview-button-blocks";
#interface UIAlertView()
- (void) runBlock: (void (^)())block;
#end
#implementation UIAlertView (WithBlocks)
/**
* Initialized an alert view with a title and message.
*/
- (id) initWithTitle:(NSString *)title message:(NSString *)message
{
self = [self initWithTitle:title message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:nil];
if (self) {
self.delegate = self;
NSMutableArray *buttonBlocks = [NSMutableArray array];
objc_setAssociatedObject(self, BUTTON_BLOCK_KEY, buttonBlocks, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return self;
}
/**
* Adds a button with a title and a block to be executed when that button is tapped.
*/
- (void) addButtonWithTitle:(NSString *)title andBlock:(void (^)())block
{
// Add the button
[self addButtonWithTitle:title];
NSMutableArray *buttonBlocks = objc_getAssociatedObject(self, BUTTON_BLOCK_KEY);
if (!block) {
block = ^{ /* empty block */ };
}
[buttonBlocks addObject:[[[block copy] retain] autorelease]];
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
NSMutableArray *buttonBlocks = objc_getAssociatedObject(self, BUTTON_BLOCK_KEY);
void (^block)() = (void (^)()) [buttonBlocks objectAtIndex:buttonIndex];
// Due to a timing issue, the current window is still the UIAlertView for a very
// short amount of time after it has been dismissed which messes up anything
// trying to get the current window in the blocks being run.
// Ergo, the block is being delayed by a tiny bit. (Amount determined through limited testing)
[self performSelector:#selector(runBlock:) withObject:block afterDelay:0.25];
}
- (void) runBlock: (void (^)())block
{
block();
}
#end
Then you can call chain the alertviews together by the following code
void(^continueBlock)(void) = ^{
// Display more alertviews here
};
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Title" message:#"message"];
[alert addButtonWithTitle:#"Continue" andBlock:continueBlock];
[alert addButtonWithTitle:#"Dismiss" andBlock:^{
// Display more alertviews here
}
[alert show];
[alert release];
I was looking for a solution to this problem as well. Here's the way I ended up solving it for my own app:
static BOOL alertShowing = FALSE;
UIAlertView *alert0 = [[UIAlertView alloc] initWithTitle:#"AlertView 0" message:#"This is the first alert" delegate:self cancelButtonTitle:nil otherButtonTitles:#"Yes",#"No", nil];
[alert0 setTag:0];
alertShowing = TRUE;
[alert0 show];
while (alertShowing) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.2]];
}
UIAlertView *alert1 = [[UIAlertView alloc] initWithTitle:#"AlertView 1" message:#"This is the second alert" delegate:self cancelButtonTitle:nil otherButtonTitles:#"Yes",#"No", nil];
[alert1 setTag:1];
alertShowing = TRUE;
[alert1 show];
while (alertShowing) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.2]];
}
// add some more alerts here for dramatic effect ...
Your button handler must set alertShowing = FALSE' in every exit path.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
// Deal with handling responses for your different alerts here.
switch ([alertView tag]) {
case 0:
// handler first alert here
break;
case 1:
// handler second alert here
break;
default:
// etc.
break;
}
alertShowing = FALSE;
}
There may be better ways to sit and spin than creating a new run loop, and there's some duplicate code that probably could be genericized better. On the plus side, it's straightforward and doesn't require a bunch of queuing logic. I'm using a #define for this pattern to keep from having to hand-type it, and it has worked fine in my case.
Here's how I did it using a queue of alert's like you suggested.
#property (strong, nonatomic) NSMutableArray *alertQueue;
#property (nonatomic) BOOL showingAlert;
- (void)showAlert:(UIAlertView *)alert {
if (self.showingAlert) {
[self.alertQueue addObject:alert];
}
else {
self.showingAlert = YES;
[alert show];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if ([self.alertQueue count]) {
UIAlertView *alert = [self.alertQueue objectAtIndex:0];
[self.alertQueue removeObjectAtIndex:0];
[alert show];
}
else self.showingAlert = NO;
}
Then whenever you want to display an alert, you just create the UIAlertView and pass it to the showAlert method and it will only show up after all earlier alerts have been dismissed.

Adding a UIImage from the UIImagePickerController to a UIButton

I have a UIButton which the user clicks on to bring up a UIImagePickerController. Once this has processed, it returns an edited UIImage to a delegate handler, which then is supposed to populate the UIButton with the new image.
In practise, however, what happens is if the user selects an image from their library, it works fine. But if they take a picture using the camera and edit it, the image doesn't make it to the UIButton. However, if I put the same image into a UIImageView for test purposes, it shows up.
Moreover, this works fine in the Simulator, but doesn't work on the device. Is it some kind of memory issue? Here's my code:
- (IBAction)takePictureButtonTapped
{
UIActionSheet *popupQuery = [[UIActionSheet alloc]
initWithTitle:nil
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:#"Take a Photo", #"Upload from Library", nil];
popupQuery.actionSheetStyle = UIActionSheetStyleBlackOpaque;
[popupQuery showInView:self.view];
[popupQuery release];
}
- (void)actionSheet:(UIActionSheet *)actionSheet
clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSLog(#"actionSheet:clickedButtonAtIndex:%d", buttonIndex);
if(buttonIndex == 2)
{
// cancel
[imagePickerController release];
}
else
{
imagePickerController = [[[UIImagePickerController alloc] init] autorelease];
imagePickerController.delegate = self;
imagePickerController.allowsEditing = YES;
if (buttonIndex == 0)
{
// Take a photo
// Set up the image picker controller and add it to the view
imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
}
else if (buttonIndex == 1)
{
// Upload from Library
imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary] == NO)
imagePickerController.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
}
[self presentModalViewController:imagePickerController animated:YES];
}
}
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingImage:(UIImage *)img
editingInfo:(NSDictionary *)editInfo
{
NSLog(#"imagePickerController::didFinishPickingImage:%#", img);
itemImage = img;
[itemImage retain];
[imageButton setBackgroundImage:itemImage forState:UIControlStateNormal];
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
}
I've tried setImage, setBackgroundImage, for ALL states, and none of them work. Yet if I put the same image into a UIImageView, it's fine.
Any ideas?
I discovered that the reason it wasn't working properly was because I was using didFinishPickingImage:editingInfo: which is DEPRECATED. I should've been using imagePickerController:didFinishPickingMediaWithInfo: instead. Now it's working perfectly!
For some reason XCode wasn't warning me of the deprecation.