I am new in iOS development.
I learnt about Delegate (Single Observer) and also NSNotificationCenter to listen to event.
Now I want to pop up an alert view when an event in a manager class happens. May I know if there's a way to pop it up regardless which view controller is showing? From my understanding, NSNotificationCenter allows me to show a alert but I have to implement the show up method on each of the view controller class. Is it a better way to do it?
Thank you!
If you just want to show up a native alert view, you can use AppDelegate class as a listener to NSNotoficationCenter, because native alert view will be added to top window directly.
If you are worry about the fact to implement your alert in every controller, you shouldn't.
They are many ways to solve that issue, you could for instance :
Subclass UIViewController, and implement a method inside that will display your alert. Just keep in mind that everytime you'll use a UIViewController, use your subclassed controller instead.
You could use protocols (objective C) or extensions (swift), to add a function that will display your alert view. In that case you don't even need to subclass anything :
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Extensions.html
Also don't forget that in swift, any properties can be listened natively. For instance, when you set your property you can do this :
var myProperty : String {
willSet {
doSomething()
}
didSet {
presentMyAlertController()
}
}
Related
I have custom UITextView:
public partial class EditableDescriptionTextView : UITextView, IUITextViewDelegate
{
ctors()...//Invokes Initialize();
void Initialize()
{
Delegate = this;
}
//Override methods I need to handle
}
In my View I have a binding to the ViewModel like so:
bindingSet.Bind(EditableDescriptionTextView)
.To(vm => vm.Description);
The problem is that firstly works that string: Delegate = this . It Ok, but when works bindingSet.Bind(...).To(...) seems that delegate changes and application crashes with exception like :
Event registration is overwriting existing delegate. Either just use events or your own delegate
The same error happens when I directly try to assign delegate after bindings like:
// CustomDelegate extends UIViewTextDelegate
EditableDescriptionTextView.Delegate = new CustomDelegate();
In other words, app fails each time when I reassign the delegate. Is there any possibility to use my own delegate with MvvmCross or what is the best workaround of this situation?
P.S.: Originally I need to implement functional like here
ShouldChangeTextInRange is not called for UITextView , but I also need mvvxcross binding.
This doesn't seem like a MvvmCross problem. MvvmCross does not attach any delegates to UITextFields. But since you are implementing your own Delegate, eventhandlers that MvvmCross uses to listen to changes in such views for TwoWay bindings, will probably not work after you have attached your custom delegate.
So I would simply stick to the events that UITextField provides you.
I have a project in which I need to log an analytics event whenever any View Controller (log the name of the View Controller) comes on screen.
I was trying to avoid littering all of my existing View Controller classes with call to the analytics SDK.
I tried making an AnalyticsViewController and all my View Controllers would subclass this View Controller, and then I add analytics event in AnalyticsViewController class's viewDidLoad method. But the problem with this approach is that AnalyticsViewController does not which child View Controller is the call coming from.
I am using Swift 3.0. I believe that Swift with its powerful language features should be able provide me with an abstraction of some sorts.
Is there any way through this problem without littering all the View Controllers?
You were on the right track. Making a UIViewController parent class is a good idea.
In viewDidLoad method you can just add this:
let className = NSStringFromClass(self.classForCoder)
It will give you the name of current loaded view controller and then you can use that name in your event to specify which view controller was actually loaded.
Edit: added example.
So your parent's viewDidLoad would look something like this:
override func viewDidLoad() {
super.viewDidLoad()
let className = NSStringFromClass(self.classForCoder)
sendEvent(withViewControllerName: className)
}
The answer given by #JPetric is an amazing starting point. I just had to do a little modification to get it to work.
I've put this in my AnalyticsViewController to retrieve the name of the current subclass.
private func currentClassName() -> String? {
return NSStringFromClass(self.classForCoder).components(separatedBy: ".").last
}
I'm working on iOS 8 custom keyboard extension right now, and there are some issues that I cannot figure out.
First, I think the UITextInputDelegate Methods are not working as I expected.
Does this sound right: selectionWillChange: and selectionDidChange: methods should be called when user long-presses typing area? And textWillChange: and textDidChange: methods should be called whenever the text is literally changing?
Actually, what I observed is that, when I changed selection in text input area, textWillChange: and textDidChange: are called, and I cannot get a clue that the other two methods are called in what condition. If anyone knows about the usage of these delegate methods, please let me know.
Second, I know the playInputClick: method can be used to virtualize keyboard click sound in custom keyboard. As this is applicable in a normal situation, I found it impossible to apply in iOS 8 custom keyboard extension. My app consists of one keyboard view controller, and custom view that subclasses UIView is added to this view controller. My approach is that UIInputViewAudioFeedback delegate is declared in this custom view, enableInputClicksWhenVisible method is returning YES, class method that calls [[UIDevice currentDevice] playInputClick] is set, then this method is called wherever the keyboard sound is needed: which is not working at all.
Is my approach is wrong in any way? If anyone has succeeded in using playInputClick method, please share your wisdom.
Thank you
It is best to play the Audio on a queue rather than in the UI key handler
func playPressKeySound() {
let PRESS_KEY_DEFAULT_SOUND_ID: SystemSoundID = 1104
dispatch_async(dispatch_get_main_queue()) {
AudioServicesPlaySystemSound(PRESS_KEY_DEFAULT_SOUND_ID)
}
}
NOTE: this only works if the keyboard has Full Access switched on, so best test there is full access before calling, otherwise the keyboard can suffer long pauses.
For the second question, try AudioServicesPlaySystemSound
#define PRESS_KEY_DEFAULT_SOUND_ID 1104
- (void)playPressKeySound {
if (self.openPressSound) {
AudioServicesPlaySystemSound(PRESS_KEY_DEFAULT_SOUND_ID);
}
}
The background:
I have an app with 5 tabs. The first time a user navigates to each tab, I would like to show a one-time "tutorial". I intend to do this by creating a "TutorialViewController" that will handle displaying these "tutorial" views and will have buttons for next/back etc...
The problem:
I'm not sure the best pattern to use for implementing the logic for whether or not to show these screens and instantiating the "TutorialViewController" to display them. The goal is to have a single line of code (a single method call) that would show the tutorial if necessary. I'm trying to avoid duplication of code across the 5 view controllers. The problem is where/how to implement this single method. As a class method on TutorialViewController? As a global C function?
Things I've considered:
1) Implementing a class method on TutorialViewController called "displayTutorialIfNecessary". In this case, each view controller that has a tutorial would call this class method from their "viewDidAppear" methods. This class method would check to see if the tutorial has already been shown, and if not, it would instantiate a TutorialViewController object to handle to display it. In this option, I guess I would have to pass in "self" from each calling view controller and the class method would use that to display the TutorialViewController.
2) Implementing a class method on TutorialViewController called "tutorialShouldBeDisplayedForScreen: ". In this option, each calling view controller would call this method, and if it returns true, each vc would instantiate and present the "TutorialViewController" which would handle displaying the tutorial.
I'm sure there is a "best practice" or a pattern that fits this scenario, but I'm not sure what the best implementation is. Thanks in advance for your recommendations.
To summarize: Instead of having something like this in each view controller:
if ([TutorialViewController shouldDisplayTutorialForScreen:<someEnum>])
{
TutorialViewController *myTutorialVC = [[TutorialViewController alloc] init];
[self displayModalViewController: myTutorialVC];
}
I'd like something more like this:
[FirstUseViewController displayTutorialIfNecessaryForScreen: <someEnum> forParentViewController: self];
store the tutorial has shown state into NSUserDefaults and use factory method design pattern to let each UIViewController you'll need create and return tutorial UIViewController like:
- (UIViewController *)tutorialVC {
return [[MYHomeScreenTutorialVC alloc] init];
}
I am building an interface, where I can add events like in a calendar.
In the AddAEventViewController I have Buttons to set the starttime, duration and recurrence.
Every time you press a button a viewcontroller comes up with a UIDatePicker, where you can set your time. The picked component is than displayed in a UITextField. Now when I press the Done-Button, it dismisses the ModalViewController and I am back to my AddAEventViewController. Next to the Durationbutton e.g. is a UILabel, where I want to show now the just picked and in the textfield shown duration.
How do I get access to the AddEventViewController out of an other ViewController? I tried to alloc and init a new one there, but it didnt work!
- (IBAction)pressedDoneButton:(id)sender {
_mainAddWishViewController.labelDuration.text=textFieldDuration.text;
[self dismissModalViewControllerAnimated:YES];
}
Can someone help me please!
Thank you Jules
There are several ways you can do this, all of them documented here. Reading and understanding them will help you a lot in iOS software development.
There are many ways to achieve this. Here is one that is fairly straightforward.
In the "child" viewController, add a delegate property and set it to the parent view controller.
Then in your Done button handler, do something like:
[self.delegate performSelector:#selector(didComplete) withObject:self]
In the parent view controller, define a method as follows:
- (void) didComplete: (YourSubViewControllerClass *) sender
{
self.labelDuration.text = sender.textFieldDuration.text
}
Basically, this implements an informal protocol whereby the subViewController informs the main view controller that it is finished and input values are available.
Note that if you cancel out of the subViewController, don't send the didComplete message.