Unexpected Identifier SLComposerView - ios

Hey everyone running into major errors where I'm being told the SLComposerViewController is unrecognizable. No visible interface for UIController and an expected identifier on my else statement when it's written correctly. It is also not recognizing my actionContoller or my twitterVC. I am in school and this is the code example I was given I have checked it and triple checked it and it is written verbatim to the intructed example which is leaving me confused as there are 12 errors in all. Any help anyone can give me to correct these errors would be great!
// ViewController.m
// SocialNetworkApp
//
// Created by Jessy on 2/12/18.
// Copyright © 2018 A3LeversPeer. All rights reserved.
//
#import "ViewController.h"
#import "Social/Social.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UITextView *tweetTextView;
- (void) configureTweetTextView;
- (void) showAlertMessage: (NSString *) myMessage;
#property (weak, nonatomic) IBOutlet UITextView *fbTextView;
#property (weak, nonatomic) IBOutlet UITextView *socialTextView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self configureTweetTextView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void) showAlertMessage:(NSString *) myMessage {
UIAlertController *alertController;
alertController = [UIAlertController alertControllerWithTitle:#"TwitterShare" message:myMessage preferredStyle: UIAlertControllerStyleAlert];
[alertController addAction: [UIAlertAction actionWithTitle:#"Okay" style:UIAlertActionStyleDefault handler:nil]];
[self presentViewController:alertController animated:YES completion:nil];
}
- (IBAction)tweetShareAction:(id)sender {
if ([self.tweetTextView isFirstResponder]) {
[self.tweetTextView resignFirstResponder];
}
UIAlertController *actionController = [UIAlertController alertControllerWithTitle:#"" message:#"Tweet Notes" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction =[UIAlertAction actionWithTitle:#"Cancel" style: UIAlertActionStyleDefault handler:nil];
UIAlertAction *tweetAction =[UIAlertAction actionWithTitle:#"Tweet"style: UIAlertActionStyleDefault handler:
^(UIAlertAction *action) {
if([SLComposeViewController
isAvailableForServiceType:SLServiceTypeTwitter]
(SLComposeViewController *twitterVC= [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter]);
}];
//Tweet Out
if( [self.tweetTextView.text length] <140 ) {
[twitterVC setInitialText:self.tweetTextView.text];
}
else{
NSString *shortText = [self.tweetTextView.text substringToIndex:140];
}
[self.presentedViewController: twitterVC animated:YES completion:nil];
}
else{
//Raise Objection
[self showAlertMessage:#"Sign in to Twitter"];
[actionController addAction:tweetAction];
[actionController addAction:cancelAction];
[self presentViewController:actionController animated:YES completion:nil];
- (void) configureTweetTextView {
self.tweetTextView.layer.backgroundColor =[UIColor colorWithRed: 0.98
green: 0.80 blue: 0.93
alpha: 1.0].CGColor;
self.tweetTextView.layer.cornerRadius= 10.0;
self.tweetTextView.layer.borderColor= [UIColor colorWithWhite: 0
alpha: 0.5].CGColor;
self.tweetTextView.layer.borderWidth= 2.0;
}
- (IBAction)fbShareAction:(id)sender {
}
- (IBAction)socialShareAction:(id)sender {
}
- (IBAction)nothingShareAction:(id)sender {
}
#end

Try to replace:
#import "Social/Social.h"
By:
#import <Social/Social.h>
Social is Apple's framework, so you should import it with <> sign.
By the way, check your Target -> General -> Linked Frameworks and Libraries that you included in Social.framework.

Related

How I know that, any changes/modification is done or not in UITextField and UITextView?

Here is my View,
In this view, except Description field all are UITextfield and Description field is UITextView.
So what I want is that when I navigate to this view,
If I made some changes or modification then only save button will be enabled
And If I edited some fields' values and tried to go back to previous screen without saving it, following alert should pop up.
How to achieve it ? Thanks.
check following example, I hope it will help you.
#import "SampleViewController.h"
#interface SampleViewController ()
#end
#implementation SampleViewController
- (void)viewDidLoad {
[super viewDidLoad];
_textview.delegate = self;
_secondButton.hidden = YES;
self.textview.layer.borderWidth = 2.0f;
self.textview.layer.borderColor = [[UIColor grayColor] CGColor];
self.navigationItem.hidesBackButton = YES;
UIBarButtonItem *newBackButton = [[UIBarButtonItem alloc] initWithTitle:#"< back" style:UIBarButtonItemStylePlain target:self action:#selector(back:)];
self.navigationItem.leftBarButtonItem = newBackButton;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)textViewDidBeginEditing:(UITextView *)textView{
_secondButton.hidden = NO;
}
- (void) back:(UIBarButtonItem *)sender {
UIAlertController* alert = [UIAlertController alertControllerWithTitle:#"Attention"
message:#"Are you sure want to discard this message."
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
self.textview.text = nil;
[self.navigationController popViewControllerAnimated:YES];
}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
NSLog(#"sandip");
[self.navigationController popViewControllerAnimated:YES];
}
- (IBAction)secondButton:(id)sender {
}
#end
Use a validator functions to validate the whole form by checking if any of the fields text count is > 0. To make your life easier, there are a few validators out there, which you can use such as, RAFieldValidator. Look out for more on github. Check these out https://github.com/search?utf8=%E2%9C%93&q=form+validator+ios&type=
Coming to triggering this function,
For Text field: check this out, UITextField text change event
For TextView: You need to set UITextView delegate and implement textViewDidChange: Method in it.

AlertViewController should not be dismissed when I enter empty AlertView textfield in iOS

I have added a textfield in AlertViewController. I don't type anything in the textfield and enter the OK button meaning dismiss the alert view. How should I check the alert textfield length is zero so that alert button actions are disabled. Please help me...
Try this code.
//
// ViewController.m
// AlertControllerDemo
//
// Created by Nilesh on 8/10/16.
// Copyright © 2016 Nilesh. All rights reserved.
//
#import "ViewController.h"
#interface ViewController ()<UITextFieldDelegate>
#property(nonatomic, strong)UIAlertAction *okAction;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)showAlertButtonAction:(id)sender {
self.okAction = [UIAlertAction actionWithTitle:#"Okay"
style:UIAlertActionStyleDefault
handler:nil];
self.okAction.enabled = NO;
UIAlertController *controller = [UIAlertController alertControllerWithTitle:nil
message:#"Please Enter your text"
preferredStyle:UIAlertControllerStyleAlert];
[controller addTextFieldWithConfigurationHandler:^(UITextField *textField) {
textField.delegate = self;
}];
[controller addAction:self.okAction];
[self presentViewController:controller animated:YES completion:nil];
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
NSString *finalString = [textField.text stringByReplacingCharactersInRange:range withString:string];
[self.okAction setEnabled:(finalString.length >= 1)];
return YES;
}
#end

Core location wont work

I have been trying to make an app that allows the user to retrieve the current location using the core location framework. I wanted to be able to get the coordinates of the device that is using the app when the app launches and be able to display them using UILabels. Can someone please tell me what i am doing wrong or what adjustments I should make to the code?
Header file:
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#interface ViewController : UIViewController
#property (strong, nonatomic) IBOutlet UILabel *longitude;
#property (strong, nonatomic) IBOutlet UILabel *latitude;
#property (strong, nonatomic) IBOutlet UILabel *altitude;
#property (strong, nonatomic) IBOutlet UILabel *speed;
#end
Implementation file:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
CLLocationManager *locationManager;
[super viewDidLoad];
locationManager = [[CLLocationManager alloc]init]; // initializing locationManager
locationManager.delegate = self; // I set the delegate of locationManager to self.
locationManager.desiredAccuracy = kCLLocationAccuracyBest; // setting the accuracy
[locationManager startUpdatingLocation]; //requesting location updates
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
UIAlertView *errorAlert = [[UIAlertView alloc]initWithTitle:#"Error" message:#"There was an error retrieving your location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles: nil];
[errorAlert show];
NSLog(#"Error: %#",error.description);
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *crnLoc = [locations lastObject];
_latitude.text = [NSString stringWithFormat:#"%.8f",crnLoc.coordinate.latitude];
_longitude.text = [NSString stringWithFormat:#"%.8f",crnLoc.coordinate.longitude];
_altitude.text = [NSString stringWithFormat:#"%.0f m",crnLoc.altitude];
_speed.text = [NSString stringWithFormat:#"%.1f m/s", crnLoc.speed];
}
#end
I get these 2 errors.
Assigning to 'id<CLLocationManagerDelegate> _Nullable' from incompatible type 'ViewController *const __strong'
'UIAlertView' is deprecated: first deprecated in iOS 9.0 - UIAlertView is deprecated. Use UIAlertController with a preferredStyle of UIAlertControllerStyleAlert instead
You're not implementing the CLLocationManagerDelegate protocol, which is why you get the first error. You could implement it like this:
#interface ViewController () <CLLocationManagerDelegate>
#end
You should also check the documentation for the methods that you'll need to implement in order to conform to that protocol, which you'll have to write in your #implementation. Only after conforming to that protocol is this assignment allowed:
locationManager.delegate = self; // I set the delegate of locationManager to self.
The second issue appears to be a warning. Apple did deprecate UIAlertView in iOS 9.0 and it has been replaced by UIAlertController, so you should use that instead. This NSHipster article explains how to use and compares it with the old, deprecated, version, which is interesting, but it's in Swift (I'm leaving it for the discussion they present). Here you'll also find some examples in Objective-C. Here's an example as shown on that last link:
UIAlertController * view= [UIAlertController
alertControllerWithTitle:#"My Title"
message:#"Select you Choice"
preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction* ok = [UIAlertAction
actionWithTitle:#"OK"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
//Do some thing here
[view dismissViewControllerAnimated:YES
completion:nil];
}];
UIAlertAction* cancel = [UIAlertAction
actionWithTitle:#"Cancel"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
[view dismissViewControllerAnimated:YES completion:nil];
}];
[view addAction:ok];
[view addAction:cancel];
[self presentViewController:view animated:YES completion:nil];

How to dismiss an UIAlertController and the keyboard simultaneously?

I have created a signup form with a UIAlertController and used the method addTextFieldWithConfigurationHandler to add a text field. But there is a little problem.
When the form shows up, the keyboard and modal appear with a smooth animation. When closing the form, the modal disappears first, and then the keyboard disappears. This makes the keyboard make a sudden downward fall.
How can I make the modal and keyboard graciously disappear?
lazy var alertController: UIAlertController = { [weak self] in
let alert = UIAlertController(title: "Alert", message: "This is a demo alert", preferredStyle: .Alert)
alert.addTextFieldWithConfigurationHandler { textField in
textField.delegate = self
}
alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
return alert
}()
#IBAction func alert() {
presentViewController(alertController, animated: true, completion: nil)
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
alertController.dismissViewControllerAnimated(true, completion: nil)
return true
}
You can set your view controller or other object as transitioning delegate of your UIAlertController (alert.transitioningDelegate) and make a custom animation for dismissing.
Code sample:
#interface ViewController () <UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning, UITextFieldDelegate>
#property (assign, nonatomic) NSTimeInterval keyboardAnimationDuration;
#property (assign, nonatomic) CGFloat keyboardHeight;
#property (nonatomic, strong) UIAlertController *alertController;
#property (nonatomic,strong) id <UIViewControllerTransitioningDelegate> transitioningDelegateForAlertController;
#end
#implementation ViewController
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self subscribeForKeyboardNotification];
}
#pragma mark - Keyboard notifications
- (void)subscribeForKeyboardNotification {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillAppear:)
name:UIKeyboardWillShowNotification
object:nil];
}
- (void)keyboardWillAppear:(NSNotification *)notification {
self.keyboardAnimationDuration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
self.keyboardHeight = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
}
#pragma mark - IBAction
- (IBAction)showAlertButtonPressed:(id)sender {
[self showAlert];
}
- (void)showAlert {
self.alertController = [UIAlertController alertControllerWithTitle:#"Alert"
message:#"This is a demo alert"
preferredStyle:UIAlertControllerStyleAlert];
__weak typeof(self) weakSelf = self;
[self.alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
textField.delegate = weakSelf;
}];
self.transitioningDelegateForAlertController = self.alertController.transitioningDelegate;
self.alertController.transitioningDelegate = self;
[self.alertController addAction:[UIAlertAction actionWithTitle:#"Ok"
style:UIAlertActionStyleCancel
handler:nil]];
[self presentViewController:self.alertController animated:YES completion:nil];
}
#pragma mark - UITextFieldDelegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[self.alertController dismissViewControllerAnimated:YES completion:nil];
return YES;
}
#pragma mark - UIViewControllerTransitioningDelegate
- (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented
presentingController:(UIViewController *)presenting
sourceController:(UIViewController *)source {
return [self.transitioningDelegateForAlertController animationControllerForPresentedController:presented
presentingController:presenting
sourceController:source];
}
- (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
return self;
}
#pragma mark - UIViewControllerAnimatedTransitioning
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext {
return self.keyboardAnimationDuration ?: 0.5;
}
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
UIViewController *destination = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
if ([destination isBeingPresented])
[self animatePresentation:transitionContext];
else
[self animateDismissal:transitionContext];
}
- (void)animatePresentation:(id <UIViewControllerContextTransitioning>)transitionContext {
NSTimeInterval transitionDuration = [self transitionDuration:transitionContext];
UIViewController *fromController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *container = transitionContext.containerView;
fromController.view.frame = container.bounds;
toController.view.frame = container.bounds;
toController.view.alpha = 0.0f;
[container addSubview:toController.view];
[fromController beginAppearanceTransition:NO animated:YES];
[UIView animateWithDuration:transitionDuration
animations:^{
toController.view.alpha = 1.0;
}
completion:^(BOOL finished) {
[fromController endAppearanceTransition];
[transitionContext completeTransition:YES];
}];
}
- (void)animateDismissal:(id <UIViewControllerContextTransitioning>)transitionContext {
NSTimeInterval transitionDuration = [self transitionDuration:transitionContext];
UIViewController *fromController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
[toController beginAppearanceTransition:YES animated:YES];
[UIView animateWithDuration:transitionDuration
animations:^{
fromController.view.alpha = 0.0;
[fromController.view endEditing:YES];
CGRect frame = fromController.view.frame;
frame.origin.y += self.keyboardHeight / 2;
fromController.view.frame = frame;
}
completion:^(BOOL finished) {
[toController endAppearanceTransition];
[transitionContext completeTransition:YES];
}];
}
#end
Result:
P.S.: I used old alert's transitioning delegate for presentation because I can't reproduce an original animation. So animatePresentation: method is never used.
I had the exact same problem you had and found the solution incidentally. You probably don't need this anymore, but for the sake of others like me, here is the answer:
Swift:
override func canBecomeFirstResponder() -> Bool {
return true
}
Objective-C:
- (BOOL)canBecomeFirstResponder {
return true;
}
Just add this code in the view controller handling the alert. Only tested in swift.
Its pretty simple.
if your UIAlertController delegate are present in self View Controller. then you can do it in its delegate method for Dismiss AlertController. You can [youtTextField resignFirstResponder] in your UIAlertController object which have a button for dismiss it. (like OK or Cancel) so your presented KeyBoard will be dismissed.
I didn't tried it but It will work. but you have to handle textField and Alert correctly.
I assume the jumping down of the UIAlertController is if it dismisses after you press 'return' on the keyboard. If so, I have found a way for the Alert and keyboard to dismiss smoothly from a return action.
You will need declare the UIAlertController within the class file
#property (strong, nonatomic) UIAlertController *alertController;
And you will also need to use the UITextFieldDelegate with the viewController
When adding the textField to the UIAlertController this is where you will need to set the delegate of it to self. (weakSelf used as it is within a block)
#interface ViewController ()<UITextFieldDelegate>
Within the method you are auctioning the UIAlertController -
self.alertController = [UIAlertController alertControllerWithTitle:#"Alert" message:#"This is the message" preferredStyle:UIAlertControllerStyleAlert];
__weak typeof(self) weakSelf = self;
[self.alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
textField.delegate = weakSelf;
}];
[self presentViewController:self.alertController animated:YES completion:nil];
Add this UITextField delegate method which will fire once the return button has been pressed on the keyboard. This means you can action for the UIAlertController to dismiss just prior to the keyboard dismissing, thus it makes it all work smoothly.
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
[self.alertController dismissViewControllerAnimated:YES completion:nil];
return YES;
}
I've tested this and should work exactly the way you require.
Thanks,
Jim
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
[self.view endEditing:YES];
// or you can write [yourtextfield refignFirstResponder]
[alertView dismissWithClickedButtonIndex:buttonIndex animated:TRUE];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex==1) {
[[alertView textFieldAtIndex:0] resignFirstResponder];
} else {
[[alertView textFieldAtIndex:0] resignFirstResponder];
}
}
Use your button index (Ok or Cancel button index)
no need to do any thing you just have to implement this much of code, it works for me, no need to declare any kind of delegate methods
- (void)showAlert {
self.alertController = [UIAlertController alertControllerWithTitle:#"Alert"
message:#"Enter Name:"
preferredStyle:UIAlertControllerStyleAlert];
[self.alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
}];
[self.alertController addAction:[UIAlertAction actionWithTitle:#"Ok"
style:UIAlertActionStyleCancel
handler:nil]];
[self presentViewController:self.alertController animated:YES completion:nil];
}
Swizzle viewWillDisappear method for UIAlertController, and perform resignFirstResponder on correspodent text field or call endEditing: on controller's view
I am using for this ReactiveCocoa:
let alert = UIAlertController(title: "", message: "", preferredStyle: .Alert)
alert.addTextFieldWithConfigurationHandler {
textField in
}
let textField = alert.textFields!.first!
alert.rac_signalForSelector(#selector(viewWillDisappear(_:)))
.subscribeNext {
_ in
textField.resignFirstResponder()
}

iOS dismiss UIAlertView beforing showing another

I have a Utils class which shows UIAlertView when certain notifications are triggered. Is there a way to dismiss any open UIAlertViews before showing a new one?
Currenty I am doing this when the app enters the background using
[self checkViews:application.windows];
on applicationDidEnterBackground
- (void)checkViews:(NSArray *)subviews {
Class AVClass = [UIAlertView class];
Class ASClass = [UIActionSheet class];
for (UIView * subview in subviews){
if ([subview isKindOfClass:AVClass]){
[(UIAlertView *)subview dismissWithClickedButtonIndex:[(UIAlertView *)subview cancelButtonIndex] animated:NO];
} else if ([subview isKindOfClass:ASClass]){
[(UIActionSheet *)subview dismissWithClickedButtonIndex:[(UIActionSheet *)subview cancelButtonIndex] animated:NO];
} else {
[self checkViews:subview.subviews];
}
}
}
This makes it easy on applicationDidEnterBackground as I can use application.windows
Can I use the AppDelegate or anything similar to get all the views, loop through them and dismiss any UIAlertViews?
for (UIWindow* window in [UIApplication sharedApplication].windows) {
NSArray* subviews = window.subviews;
if ([subviews count] > 0)
if ([[subviews objectAtIndex:0] isKindOfClass:[UIAlertView class]])
[(UIAlertView *)[subviews objectAtIndex:0] dismissWithClickedButtonIndex:[(UIAlertView *)[subviews objectAtIndex:0] cancelButtonIndex] animated:NO];
}
iOS6 compatible version:
for (UIWindow* w in UIApplication.sharedApplication.windows)
for (NSObject* o in w.subviews)
if ([o isKindOfClass:UIAlertView.class])
[(UIAlertView*)o dismissWithClickedButtonIndex:[(UIAlertView*)o cancelButtonIndex] animated:YES];
iOS7 compatible version:
I made a category interface that stores all instance in init method.
I know it's a very inefficient way.
#import <objc/runtime.h>
#import <objc/message.h>
#interface UIAlertView(EnumView)
+ (void)startInstanceMonitor;
+ (void)stopInstanceMonitor;
+ (void)dismissAll;
#end
#implementation UIAlertView(EnumView)
static BOOL _isInstanceMonitorStarted = NO;
+ (NSMutableArray *)instances
{
static NSMutableArray *array = nil;
if (array == nil)
array = [NSMutableArray array];
return array;
}
- (void)_newInit
{
[[UIAlertView instances] addObject:[NSValue valueWithNonretainedObject:self]];
[self _oldInit];
}
- (void)_oldInit
{
// dummy method for storing original init IMP.
}
- (void)_newDealloc
{
[[UIAlertView instances] removeObject:[NSValue valueWithNonretainedObject:self]];
[self _oldDealloc];
}
- (void)_oldDealloc
{
// dummy method for storing original dealloc IMP.
}
static void replaceMethod(Class c, SEL old, SEL new)
{
Method newMethod = class_getInstanceMethod(c, new);
class_replaceMethod(c, old, method_getImplementation(newMethod), method_getTypeEncoding(newMethod));
}
+ (void)startInstanceMonitor
{
if (!_isInstanceMonitorStarted) {
_isInstanceMonitorStarted = YES;
replaceMethod(UIAlertView.class, #selector(_oldInit), #selector(init));
replaceMethod(UIAlertView.class, #selector(init), #selector(_newInit));
replaceMethod(UIAlertView.class, #selector(_oldDealloc), NSSelectorFromString(#"dealloc"));
replaceMethod(UIAlertView.class, NSSelectorFromString(#"dealloc"), #selector(_newDealloc));
}
}
+ (void)stopInstanceMonitor
{
if (_isInstanceMonitorStarted) {
_isInstanceMonitorStarted = NO;
replaceMethod(UIAlertView.class, #selector(init), #selector(_oldInit));
replaceMethod(UIAlertView.class, NSSelectorFromString(#"dealloc"), #selector(_oldDealloc));
}
}
+ (void)dismissAll
{
for (NSValue *value in [UIAlertView instances]) {
UIAlertView *view = [value nonretainedObjectValue];
if ([view isVisible]) {
[view dismissWithClickedButtonIndex:view.cancelButtonIndex animated:NO];
}
}
}
#end
Start instance monitoring before using UIAlertView.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//...
//...
[UIAlertView startInstanceMonitor];
return YES;
}
Call dismissAll before showing another.
[UIAlertView dismissAll];
It's better using a singleton pattern if you can control all UIAlertViews.
But in my case, I need this code for closing javascript alert dialog in a UIWebView.
Since UIAlertView is deprecated in iOS8 in favor of UIAlertController (which is a UIViewController, presented modally), you can't preset 2 alerts at the same time (from the same viewController at least). The second alert will simply not be presented.
I wanted to partially emulate UIAlertView's behavior, as well as prevent showing multiple alerts at once. Bellow is my solution, which uses window's rootViewController for presenting alerts (usually, that is appDelegate's navigation controller). I declared this in AppDelegate, but you can put it where you desire.
If you encounter any sorts of problems using it, please report here in comments.
#interface UIViewController (UIAlertController)
// these are made class methods, just for shorter semantics. In reality, alertControllers
// will be presented by window's rootViewController (appdelegate.navigationController)
+ (UIAlertController *)presentAlertWithTitle:(NSString *)title
message:(NSString *)message
cancelButtonTitle:(NSString *)cancelButtonTitle
otherButtonTitles:(NSArray *)otherButtonTitles
handler:(void (^)(NSInteger buttonIndex))block;
+ (UIAlertController *)presentAlertWithTitle:(NSString *)title
message:(NSString *)message
cancelButtonTitle:(NSString *)cancelButtonTitle;
#end
#implementation UIViewController (UIAlertController)
+ (UIAlertController *)presentAlertWithTitle:(NSString *)title
message:(NSString *)message
cancelButtonTitle:(NSString *)cancelButtonTitle
{
return [self presentAlertWithTitle:title message:message cancelButtonTitle:cancelButtonTitle
otherButtonTitles:nil handler:nil];
}
+ (UIAlertController *)presentAlertWithTitle:(NSString *)title
message:(NSString *)message
cancelButtonTitle:(NSString *)cancelButtonTitle
otherButtonTitles:(NSArray *)otherButtonTitles
handler:(void (^)(NSInteger buttonIndex))block
{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:cancelButtonTitle style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
if (block)
block(0);
}];
[alert addAction:cancelAction];
[otherButtonTitles enumerateObjectsUsingBlock:^(NSString *title, NSUInteger idx, BOOL *stop) {
UIAlertAction *action = [UIAlertAction actionWithTitle:title style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
if (block)
block(idx + 1); // 0 is cancel
}];
[alert addAction:action];
}];
id<UIApplicationDelegate> appDelegate = [[UIApplication sharedApplication] delegate];
UIViewController *rootViewController = appDelegate.window.rootViewController;
if (rootViewController.presentedViewController) {
[rootViewController dismissViewControllerAnimated:NO completion:^{
[rootViewController presentViewController:alert animated:YES completion:nil];
}];
} else {
[rootViewController presentViewController:alert animated:YES completion:nil];
}
return alert;
}
#end

Resources