I added UIAlertController in my app by creating a category on UIViewController with the following method:
- (void)showAlertViewWithTitle:(NSString *)title
message:(NSString *)message
actions:(NSArray *)alertActions
{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title ? : #"" message:message preferredStyle:UIAlertControllerStyleAlert];
if (alertActions.count) {
for (UIAlertAction *action in alertActions) {
[alertController addAction:action];
}
} else {
UIAlertAction *action = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:nil];
[alertController addAction:action];
}
[self presentViewController:alertController animated:YES completion:nil];
}
At first, everything looks great but when I analyze leaks with Instruments, each time I call this method, some leaks appear:
Here is how the call of showAlertViewWithTitle:message:actions: is done
[self showAlertViewWithTitle:nil message:#"Test message" actions:nil];
Any idea why I get all these leaks?
-- EDIT --
I tried the following in a sample project:
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"title" message:#"message"
delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
and I get the same leaks. I'm really not sure what's going on...
This is an iOS bug.
This is also a duplicate of SO question iOS 8 Only Memory Leak with UIAlertController or UIActionSheet posted 1 day earlier.
See Apple Bug Reporter issue 21005708, Memory leak in UIAlertController under ARC.
The leak seems to be fixed with iOS 8.2 and Xcode 6.2
Related
what im trying to accomplish is on pressing the statusbar a alert pops up. im trying to learn tweak development and the tutorial im following is a bit old and uses the deprecated UIAlertView So after finding the correct header (UIAlertController) i get the following errors trying to compile the tweak. Sry if this is a noob question i googled and nowhere really gave a clear answer for it. thanks in advance.
code-
#include <UIKit/UIKit.h>
%hook SBStatusBarManager
-(void)handleStatusBarTapWithEvent:(id)arg1{
UIAlertController *alert = [[UIAlertController alloc] alertControllerWithTitle:#"My Alert" message:#"I hope this works!" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
%orig;
}
%end
Here are the errors i got trying to compile.
Tweak.x:9:55: error: no visible #interface for 'UIAlertController' declares the selector 'alertControllerWithTitle:message:preferredStyle:'
Tweak.x:13:7: error: no visible #interface for 'SBStatusBarManager' declares the selector 'presentViewController:animated:completion:'
Firstly:
alertControllerWithTitle:message:preferredStyle is a class method, so you cannot call it on an instance.
This should work:
UIAlertController* alertController = [UIAlertController alertControllerWithTitle:#"My Alert"
message:#"I hope this works!"
preferredStyle:UIAlertControllerStyleAlert]
Secondly:
SBStatusBarManager is not a UIViewController, so you need to find a suitable UIViewController that can present your alert controller.
Maybe you can try to access the root view controller, this link should help: https://stackoverflow.com/a/36879892/3227743
Then, you can present the alert view controller accordingly.
I have a class named ManagerClass.
Manager Class has a function showUIAlertController:
- (UIAlertController*)showUIAlertController:(NSString *)title message:(NSString *)message actions:(NSArray<UIAlertAction*>* )actions
This function should show alert controller with the parameters received.
So far so good...
Now i would like to take these actions and edit them somehow. Something like:
UIAlertAction *action = actions.firstObject;
UIAlertAction *actionCopyWithAdditionalAction = [UIAlertAction actionWithTitle:action.title style:action.style handler:^(UIAlertAction * _Nonnull action) {
[action "performTheAction"]; //perform the original action
[ManagerClass doSomething];
}];
"performTheAction" does not exist - it is just for you to understand what i am trying to achieve.
Does anyone has an idea how this task can be achieved ?
Did not find a way to do that while looking at Apple's UIAlertAction API
https://developer.apple.com/reference/uikit/uialertaction
Do you mean to perform a method provided by your code. Then use:
[self performSelector:#selector(aMethod:)];
or when sending an object with:
[self performSelector:#selector(aMethod:)
withObject:(id)object];
Note, the self here is referencing to the same class, it could be somewhere else as well.
Edit *
UIAlertController* alert = [UIAlertController alertControllerWithTitle:#"My Alert"
message:#"This is an alert."
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
NSLog(#"42.");
}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
The console logs out 42. Put instead every action do you need.
Why you want to call a second alert which only displays the first alert and execute some of your code? You can do that in the first alert, too.
//Create the UIAlertController
UIAlertController *theAlertController = [UIAlertController alertControllerWithTitle:#"Your Title" message:#"Your Message" preferredStyle:UIAlertControllerStyleAlert];
//Add an UIAlertAction which the user can click at
[theAlertController addAction:[UIAlertAction actionWithTitle:#"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
//Execute your own code
//[self myOwnCode];
//Close the AlertController after your code
[self dismissViewControllerAnimated:YES completion:nil];
}]];
dispatch_async(dispatch_get_main_queue(), ^{
[self presentViewController:theAlertController animated:YES completion:nil];
});
Hope i understand you right.
You could pass a alert action model instead of a UIAlertAction.
so your method would look something like this:
- (UIAlertController*)showUIAlertController:(NSString *)title message:(NSString *)message actions:(NSArray<MyActionModel*>* )actions
where MyActionModel is a class with 3 properties
#interface MyActionModel: NSObject {
#property NSString * title;
#property UIAlertActionStyle * style;
#property ((void)^(UIAlertAction *)) action;
}
Then you can create your UIAlertActions when you need them and also add in your manager callbacks.
P.S. Sorry if my Objective-C is not quite right, I'm a bit rusty.
I am using this code to show UIAlert which will ask simple input
UIAlertController *alert = [UIAlertController alertControllerWithTitle:#"Alert" message:#"Message" preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:#"Click" style:UIAlertActionStyleDefault handler:nil]];
[alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
textField.placeholder = #"Enter text:";
}];
[self presentViewController:alert animated:YES completion:nil];
Also tried this code of iOS 7
UIAlertView *alertViewCustomQuestion=[[UIAlertView alloc]initWithTitle:#"Custom Question" message:#"Please enter your custom question!" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Ok",nil];
alertViewCustomQuestion.alertViewStyle=UIAlertViewStylePlainTextInput;
[alertViewCustomQuestion show];
Both shows same result. While any example I saw has good width.
I was fixing bugs of someone's else code, Finally found there was some category that was changing its behavior.
Just adding this as a reference for someone else in the future, who might stumble upon a similar problem.
I've had a identical problem as the OP in the question above, and in my case it turned out to be PixateFreestyle framework that is being used in the project I'm working on.
Apparently the framework is not being actively developed anymore, but fortunately there is kind of a FIX for the issue.
I have an issue related to UIAlertView while running our app on iOS 8.
I am showing an alert with title as nil. It was working fine in iOS 7 but now UI looks odd.
I have attached screenshot here.
One solution I found is that when I provide empty string #“” it looks okay. See below screenshot. But I am not sure if the issue I mentioned is bug in beta iOS 8 version or if there is any other better solution. Even with the solution it's not exact as it was in iOS 7.
iOS 7 - showing alert view with title as nil. Screenshot here.
The closest I could get with iOS 8 was by setting the title instead of the message:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Location field required." message:nil delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
It should be noted, however, that UIAlertView is deprecated in iOS 8 and, if you're going to be using separate code paths for iOS 7 and iOS 8, you should be using UIAlertController instead:
UIAlertController *alert = [UIAlertController alertControllerWithTitle:#"Location field required." message:nil preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
[self dismissViewControllerAnimated:YES completion:nil];
}]];
[self presentViewController:alert animated:YES completion:nil];
I got the same results with both methods.
It has been the best practice for me to use initWithTitle:#"" for UIAlertView, UIActionSheet since iOS 6 because I was facing a design issue during that time when I was using initWithTitle:nil. I tried to find back, I couldn't find it what exactly is the reason.
From your screen shot on iOS 8, I think there is a change of view hierarchy on UIAlertView for iOS 8. I think Auto layout might be implemented on the view hierarachy as well as you can see the messageLabel jump up to the titleLabel.
I can not be sure because the view hierarchy for UIAlertView is private.
The UIAlertView class is intended to be used as-is and does not
support subclassing. The view hierarchy for this class is private and
must not be modified.
See: https://developer.apple.com/library/ios/documentation/uikit/reference/UIAlertView_Class/UIAlertView/UIAlertView.html
But, I use the code:-
NSLog(#"%#",[self.alertView description]);
Result on iOS 7.1:
<UIAlertView: 0x7fb3c05535b0; frame = (18 263; 284 62); opaque = NO; layer = <CALayer: 0x7fb3c0519810>>
Result on iOS 8.0:
<UIAlertView: 0x7bf64840; frame = (0 0; 0 0); layer = <CALayer: 0x7bf648f0>>
I am not sure why the UIAlertView frame for iOS 8 is (0 0; 0 0);
Like Mike said, I think you should learn to use UIAlertController for iOS 8.
I managed to get decent message alignment without the bold font by:
Setting the title to #"" instead of nil, and
(If IOS8) prepend a "\n" in front of the message.
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#""
message:#"\nLocation field required."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
Please try this code.
it is working on my side
xcode version 9.2
UIAlertController * alert= [UIAlertController
alertControllerWithTitle:nil
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction* btn1 = [UIAlertAction
actionWithTitle:#"OKAY"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
}];
[self presentViewController:alert animated:YES completion:nil];
I have an app that consists of several view controllers, in each view controllers I could load a UIAlertView.
What would be the best way of having a global alert view function? So I could effectively have a function bit like
[GlobalAlertVIew alertview : 2];
the 2 referring to what alert it is (bit like a enum).
I have tried adding an NSObject file and calling that, however on the return function
- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
how do I get from this file in the NSObject to the original view controller?
Thanks
You either need to configure the delegate on the configured UIAlertView
UIAlertView *alertView = [GlobalAlertView alertView:2];
alertView.delegate = self;
or expose the delegate in the factory method
[GlobalAlertView alertView:2 withDelegate:self];
I don`t know if you still need, but I did like this:
+ (void)alert: (UIViewController *) view title: (NSString *) title message: (NSString *) message;
+ (void)alert: (UIViewController *) view title: (NSString *) title message: (NSString *) message {
UIAlertController * alert= [UIAlertController
alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {}];
[alert addAction:defaultAction];
[view presentViewController:alert animated:YES completion:nil];
}
You can add the following code to your constants header file and import this header at .pch file to be able to see this file at app ,
#define SHOW_ALERT(title,msg){ UIAlertController *noDataFoundAlert = [UIAlertController alertControllerWithTitle:title message:msg preferredStyle:UIAlertControllerStyleAlert];UIAlertAction *okAction = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action){}]; [noDataFoundAlert addAction:okAction]; [self presentViewController:noDataFoundAlert animated:YES completion:nil];}
And you can call this method at any class like the following call ,
SHOW_ALERT(#"Please select any section", #"Please select any section");
Nada Gamal