Customize UIAlertController in iOS 8 to include standard elements like UITableView - customization

I am used to customize UIAlertViews through the [alert setValue:someView forKey:#"accessoryView"] method. This creates customizable content for UIAlertViews with custom heights. However it only works on iOS7 and down. In iOS8 the UIAlertController have taken over, and I cannot customize it anymore, it will cut the height of the UIAlertView.
Is it impossible because of misuse of the UIAlertController, or how am I supposed to do it?
I am trying to incorporate a UITableView inside a UIAlertController with UIAlertControllerStyleAlert.
Thx.

I ran into the same issue right now. I looked at the private header for UIAlertController (https://github.com/nst/iOS-Runtime-Headers/blob/master/Frameworks/UIKit.framework/UIAlertController.h) and found a promising property: contentViewController
And it turned out to be exactly the same as accessoryView used to be for UIAlertView, the difference being that you need to assign a UIViewController to this property rather than a UIView.
UIViewController *v = [[UIViewController alloc] init];
v.view.backgroundColor = [UIColor redColor];
[alertController setValue:v forKey:#"contentViewController"];
That piece of code will show a red view on the alert view! Happy UIAlertController customizing ;)
PS. It is a private property but using KVC there shouldn't be a problem App Store wise, I think.
Edit:
Some people complained that this isn't very safe. It's not a public API, so yes, Apple could change it in any release, causing this method to fail.
To make sure your entire app doesn't crash if that happens you could wrap the KVC call in a try block. If the property changes your controller won't show the content view, but it also won't crash:
#try {
[alertController setValue:v forKey:#"contentViewController"];
}
#catch(NSException *exception) {
NSLog(#"Failed setting content view controller: %#", exception);
}
Using this method in production can be risky, and I don't recommend it for important alerts.

I suggest not your wasting time trying to cram additional UI into a place where isn't supposed to be. Based on the last few years of improvements, Apple will probably add a custom view in the next iOS. Until then, have a look at a framework designed to handle this exact situation without subverting any best practices: SDCAlertView
It supports alerts that imitate the native alerts on iOS 7,8,9, including handling all of the nasty edge cases around sizing, button types, rotation, etc. It does support arbitrary custom views within the alert.
I use this library in Yahoo YMPromptKit for custom push notification prompts that look exactly like iOS native. Here's another example:

I think you can easily customize the UIView adding the controls needed and present it modally, unless you have any other specific reason to use only UIAlertController.
https://www.cocoacontrols.com/search?q=UIAlertview

You can do it with just a one of line of code using my UIAlertController category and replace existing alerts in application, check it here.

Related

How to query UITextField wrapped in UIViewRepresentable from a Xcode UI test?

I'm developing my app with SwiftUI, but some elements are still from the UIKit world, e.g. one UITextField with special behavior, that's why I use a UIViewRepresentable where the makeUIView methods returns a UITextField.
When I try to enter text via UI test, I don't succeed in querying the textfield; even app.textFields doesn't return anything.
Is this because of using UIViewRepresentable, am I missing something?
I had the same situation you described. Make sure to set accessibilityIdentifier in makeUIView. Also bear in mind that if you're setting isSecureTextEntry to true, you should access it using app.secureTextFields

SwiftUI: where to put app initialization code so it doesn't run in preview?

I'm trying to find where to put app initialization code that should NOT be run in preview mode. I've seen several answers suggesting it's incorrect to split the app behaviour this way (launch vs preview), but I disagree: many apps need to do additional setup (eg connect to database, launch background tasks, call APIs, etc) that isn't appropriate for the preview (where static test data makes most sense).
In preview mode, Xcode actually runs the app and calls AppDelegate.applicationDidFinishLaunching, so any post-launch initialization code there will be triggered.
What is the recommended way to run app setup code so that it doesn't run in preview?
It appears that Xcode sets an environment variable when running the app for SwiftUI previews. The key is "XCODE_RUNNING_FOR_PREVIEWS", which will have a value of "1".
Given this I found putting a guard statement that checks that environment value in my applicationDidFinishLaunching implementation before the initialization I didn't want to occur for previews fixed my preview (my initialization was making them fail entirely).
I also wrapped it in a DEBUG check to ensure it would not ever accidentally break a production build.
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Initialization needed for previews
#if DEBUG
guard ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] != "1" else {
return
}
#endif
// Further initialization not needed for previews
}
The Preview Live, I assume you mean it, creates complete window scene context and injects there view to be previewed, so all application & scene delegate methods are called including instantiating root ContentView, but the root view is not shown, ie. its body is not called.
Thus you can achieve your goal by placing code, initiating all heavy/network/etc. operations in root view's .onAppear callback. And this, actually, will be good for your users as well, because such approach gives fast application start and initial UI presented.
TL;DR:
Workaround this issue by putting your SwiftUI code in a framework and make it the selected scheme in Xcode before viewing your previews.
Details:
Looks like SwiftUI Previews need to build a target that contains the SwiftUI code (makes sense), but that target doesn't have to be an app! So it's unclear why it needs to run the app at all, but clearly it does. Xcode picks which target to build from the currently selected scheme (if you pick a target that doesn't build the required SwiftUI files, you'll get an error in the previews). So here's a workaround:
Add a new framework target
Put your view code in that new target
Select the scheme for that new target
Run your preview
This also has the advantage of only compiling the new target (and its dependencies) for rendering previews, which is likely to be faster that building the whole app.
Any dependencies will of course need to be accessible from that new target.
This works at least in Xcode 12.5.1

Popping consecutive view controllers and returning to main view controller (using navigation controller)

I'm following the Firebase-Chat-Messenger example in the "let's build that app" Youtube videos, and it works fine.
However, I'm testing integration inside a test application :
My test app has a menu with buttons and one of them is for the chat, which takes us to a similar interface (login menu and so on, anything beyond it is similar to the example in the tutorial. But you don't need to check it to answer my question).
Main menu button => Login/Register interface => Chat interface
I can't find a way to dismiss the chat interface to return to the main menu of the app, dismiss always returns to the login/register interface and sometimes causes errors. Could you suggest a good solution to use for this?
tl;dr : How to dismiss two or more views and return to main view (main menu) of app?
P.S : I'm new to Swift and still struggling with some basic elements, Sorry if the question seems too simple.
Use either popToRootViewController(animated:) to pop to the root view controller, or popToViewController(_:animated:) and provide the spicific controller you'd like to pop to.

How to make an action affect a sibling view without controller.get('view')?

Quick context:
Application view has 2 outlets. One for a toolbar. The other for the routable "main" view hierarchy.
app -- main
\-- toolbar
I need some buttons in the toolbar to trigger events in the "main" view. Not update any data in any model. I simply instruct it to trigger some changes to a drawing library that the view is presenting. Clearing the canvas, resetting zoom value and such.
In 1.0 pre2 and earlier I have used actions and router.get('someController.view') to get access to the view I want and trigger the action/method/event. Hardly the pinnacle of application design but it worked fine.
This option is now gone and I am at a loss for a good alternative. What mechanism should I use when communicating between views that are not in a child/parent hierarchy? Everything I have come up with is clunky and triggers my sense that "Ember has a better way".
In short I want:
A toolbar-button to trigger an event
The main view to react to this and perform some updates on parts of itself.
The main view to NOT re-render in the Ember sense of the word as would through routing. It uses a drawing library and integrating all it's properties and behavior into Ember models and controllers would not be a lot of fun.
The toolbar and the main view share a parent view but are on different "branches".
Poor Options I am considering:
The toolbar is very much an application level concern but it does have some buttons that need to instruct specific views. One option I see within Ember is to nest the toolbar under the "main" view. This seems wrong for some of it's other functions.
Communication could be handled by a controller (and possibly even a model) that would hold properties that the toolbar sets and the "listening" view reacts to and resets the value of. This sounds like abuse of the controller and model purposes and like a pretty poor event listener setup.
I could make the drawing library an application global as App.Drawing or something but that does also seems bad. It would also mean that the actions still would not be able to make use of any data in the view to update the drawing library with.
Any suggestions?
What mechanism should I use when communicating between views that are not in a child/parent hierarchy?
In a typical ember application this communication should happen between controllers. Otherwise "Poor Option 2" is on the right track:
Communication could be handled by a controller (and possibly even a model) that would hold properties that the toolbar sets and the "listening" view reacts to and resets the value of.
Consider using two controllers. Toolbar actions will target the ToolbarController, which is responsible for maintaining the toolbar's state and for changing main in response to user action. ToolbarController should declare a dependency on MainController via the needs property. For example:
App.ToolbarController = Ember.Controller.extend({
needs: ['main'],
buttonOneGotAllPressed: function() {
main = this.get('controllers.main');
main.turnOffAnOption();
main.makeSomeOtherChange();
}
});
Now MainController can be focused on the state of MainView. It should not be aware of ToolbarController or it's buttons.
This sounds like abuse of the controller and model purposes and like a pretty poor event listener setup.
Agreed it would likely be an abuse of model purposes but it is exactly what controllers are for.
This is definitely not an event-listener setup, but that does not seem a good fit in your case. The toolbar you describe seems to exist only to interact with the main view, so it makes sense to have a toolbar controller that depends on main and interacts with it directly.
If the components are truly decoupled then an observer (Pub/Sub) pattern might be more appropriate. See How to fire an event to Ember from another framework if that's of interest.

Disabling areas on Credential Provider

I'm working on a credential provider for windows 7 with cpp. I want to disable textboxes and submit button while the system is working in the background. For this I tried to use the code below:
_pCredProvCredentialEvents->SetFieldInteractiveState(this,SFI_EDIT_TEXT,CPFIS_DISABLED);
At here SFI_EDIT_TEXT represents the object that I want to change it's properties and CPFIS_DISABLED shows it's should be disabled (at least i assume that is). But I didn't get any useful result. Anyone can able to help?
There are a several situations, where using SetFieldInteractiveState won't work. For example, if user have pressed "Submit" button, your's provider GetSerialization function will be called, and no GUI changes will be done by LogonUI until you return from GetSerialization. I think changes of GUI are made only between calls of your provider's functions.
P.S. I know, that question was asked long time ago, but in future, maybe, my answer can help others.