I'm writing an iOS application and I'd like to pause my app's motion content when the operating system decides to show a Banner Notification like this one:
Is there a system NSNotification that I can observer or a method that gets called which I can react to? I've triedapplicationWillResignActive, but that isn't called in this case.
I took a stab at it this morning, and I'm inclined to say that there's no public API for this.
I tried using the code outlined here, and didn't catch any notifications. Then, I ran a bunch of "tests" to see if I could find anything.
To test, I created a pair of applications, one to schedule notifications (GitHub link), and one to try and "catch" them (GitHub link). In my Sender app, I can send N notifications every N seconds. I picked some arbitrarily high value and sent them.
In my catcher, I've tried looking at visibleRect values up and down the layer hierarchy. (The keyWindow lives in a layer, but it's superview, and super layer.delegate are both nil) I haven't checked constraints, but that shouldn't matter. I've looked at the application's window, it's nil superview, it's layer, it's subviews. The application's bounds aren't effected either. The app is sandboxed so well, that springboard and notification center don't exist in the app's world.
I started going down the path of accessing private frameworks, but decided it wasn't worth the effort.
I've opened Instruments and looked at the transparency levels of the views. (Is it possible to force all views in a hierarchy to be opaque, and then use that to see if the banner is blocking something? Perhaps it's not "blocking" if it's transparent?)
I've also attempted to take a screenshot, and check the colors in the top area of the screen, but that wouldn't work because you need to pass a view in to the context. Even if it would work, it wouldn't be particularly performant.
Another thought I've had would be to listen for push notifications on the push port, but I doubt that Apple would allow you to catch another app's notifications. As a developer, I wouldn't send private info in an alert, but it's still a concern.
The truth is that notification banners don't really cause your application to become inactive, so I'm not sure that this behavior is wrong. If it's a convenience, file a bug.
How about requesting DeviceWillShowNotificationNotification?
Related
I've taken over a project that handles which screen to show first in the "applicationDidBecomeActive" function inside the AppDelegate. This has been causing problems because whenever the app asks for a permission sometimes, not all, it will trigger this block of code and send the user to the incorrect screen. I'm not sure what to do since I've never encountered this before. Any ideas why this is occurring or ways to circumvent this? I've tried adding a flag variable, however, that doesn't seem to work consistently because it looks like it gets un-set before the applicationDidBecomeActive is triggered.
When system notifications such as Permissions are presented, the application is sent to background, or becomes "inactive". When the Permission notification is dismissed, the application becomes "active" again. This would explain why didBecomeActive is triggered.
https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622956-applicationdidbecomeactive
I've taken over a project that handles which screen to show first in the "applicationDidBecomeActive" function inside the AppDelegate... Any ideas why this is occurring or ways to circumvent this?
The simple answer is: don't do that work in applicationDidBecomeActive(). As you've seen, the application can become inactive and then active again while the app remains in the foreground, so that's not the right state transition for what you're doing. Identify the app state transitions where you really do want to choose a screen. For example, you might want to do it when the app launches, and also when it transitions from background to foreground, so you could use application(_:didFinishLaunchingWithOptions:) and applicationWillEnterForeground(_:). (Obviously, you don't want to put the same code in both places, so put it in a separate method and just call it from those two methods.)
Apple has a document that covers this very topic: Managing Your App's Life Cycle. There's also a lot of information on application states on the UIApplicationDelegate reference page. Both documents include helpful state transition diagrams and descriptions of what the various states mean.
As a solution; you can use the applicationWillEnterForeground(). It's being called before the applicationDidBecomeActive() and not being triggered by permission request.
I am adding camera using {[UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera]} as a subview to a UIView with fixed boundaries in my app.
Everything is working fine. But all the examples i see shows displaying camera as a modalcontroller as single screen. My doubt is, are there any cases that APPLE will reject if the camera is added as an subview to a view?. Should it be only shown as a full screen modal controller?
There is no rule that says you may not use camera view as a subview. It's all down to the specifics of your requirements and your app. Apple probably won't reject your app just because of such use of the camera view.
For example, Layar app is using camera view as a background for their overlays - clearly not a modal controller.
At the same time, consider the user's experience. If you are providing your user with the ability to take a picture with the camera and then use this picture in further application logic, then using it as a modal controller may be a better approach, as it provides the user with a consistent experience across multiple apps: users do get used to certain experiences and you need to have a valid reason to go against those consistent experiences.
At the same time, if you do have a valid reason why you want to have camera view as a subview (for example, display an overlay layer over it or apply a filter to the preview, or whatever else), then this is a perfectly valid reason for your UI design decision.
So, to summarize, there's no rule against it, but keep the user's experience in mind. Also remember that Apple may choose to reject your app for any reason they choose - and they don't have to explain it to you. At least, that's what you're agreeing to when you join the developer's programme.
UIView's that don't handle their events pass them up the chain. By default, this passes them to their parent View, and if not handled (ultimately) to their parent UIViewController.
UIScrollView breaks this (there's lots of questions on SO, variations on the theme of "why does my app stop working once I add a UIScrollView?)
UISV decides whether the event is for itself, and if not, it passes it DOWN (into its subviews); if they don't handle the event, UISV just throws it away. That's the bug.
In that case, it's supposed to throw them back up to its own parent view - and ultimately parent UIVC. AFAICT, this is why so many people get confused: it's not working as documented (NB: as views are documented; UISV simply is "undocumented" on this matter - it doesn't declare what it aims to do in this situation).
So ... is there an easy fix for this bug? Is there a category I could write that would fix UISV in general and avoid me having to create "fake" UIView subclasses who exist purely to capture events and hand them where they're supposed to go? (which makes for bug-prone code)
In particular, from Apple's docs:
If the time fires without a significant change in position, the scroll view sends tracking events to the touched subview of the content view. If the user then drags their finger far enough before the timer elapses, the scroll view cancels any tracking in the subview and performs the scrolling itself.
...if I could override that "if the timer fires" method, and implement it correctly, I believe I could fix all my UISV instances.
But:
- would apple consider this "using a private API" (their description of "private" is nonsensical in normal programming terms, and I can't understand what they do and don't mean by it)
- does anyone know what this method is, or a good way to go about finding it? (debugging the compiled ObjC classes to find the symbol names, perhaps?)
I've found a partial answer, that's correct, but not 100% useable :(.
iPhone OS 4.0 lets you remotely add listeners to a given view, via the UIGestureRecognizer class. That's great, and works neatly.
Only problem is ... it won't work on any 3.x iPhones and iPod Touches.
(but if you're targetting 4.0 and above, it's an easy way forwards)
EDIT:
On OS 3.x, I created a custom UIView subclass that has extra properties:
NSObject *objectToDelegateToOnTouch;
id touchSourceIdentifier;
Whenever a touch comes in, the view sends the touch message directly to the objectToDelegateToOnTouch, but with the extra parameter of the touchSourceIdentifier.
This way, whenever you get a touch, you know where it came from (you can use an object, or a string, or anything you want as the "identifier").
I have used to loading a default image in my appication. So i have set to,
Sleep(3); in my delegate.m class.
But sometimes it will take more than 6 to 7 minutes. So i want to display the image 3 seconds only and then it goes to my appilcation based on my requirements.
Which one is best way to do that?
Sleep(3) or [NSThread sleepForTimeInterval:3.0] or something else;
And i must display the image 3 seconds only. Please explain me.
(Note: And I declared setter and getter methods only in my deleagte class.)
Please explain me.
As Rob noted, Apple strongly recommends against a splash screen unless it hides some necessary behind the scenes process (like loading game graphics.) It is so strongly discouraged that some people have claimed that their apps have been rejected for using an unnecessary splash screen.
The default.png doesn't exist to create a splash screen. Instead it exist to allow you to create the illusion that your initial view loads faster than it does. You supposed to use it to provide an image of your initial view so that the enduser can begin to cognitively orient themselves to the interface. By the time they have oriented themselves to the interface and moved their finger to touch the interface, it is live.
Why? Because iPhone apps are supposed be quick in, quick out. People don't sit down to use them at a desk like a desktop. People use then on the go. Sometimes they use them in the middle of a conversation.
I tell my clients to test out the usability of their apps (except for games) while walking, riding an exercise bike etc as well as in the middle of a face-to-face and phone conversation. In those circumstances, a three second pause is a big deal and very noticeable especially if the app is a practical app. Imagine if every time you opened the Contact app you had to pause three seconds to see an Apple splash screen. You would get peeved in a hurry.
The key thing here is that an unnecessary splash screen doesn't add any value for the user. It is a selfish act on the part of the software publisher to eat the end users time so that the publisher can build brand recognition for the sole benefit of the publisher. Wasting three seconds of the users time every time they use the app adds up in a hurry. (In my experience, it also makes the user perceive that the overall app is slow and clunky.)
However, if you do want to shoot yourself in the foot or if you have a client hell bent on a splash screen, you do it like this:
The splash screen appears until the first view loads so you delay the loading of the first view. In the app delegates applicationDidFinishLaunching: method, remove all the code that loads the first view into the window. Replace it with a NSTimer. Put the code to load the first view in the timer's fire method.
With that setup the app will display the default.png as it launches, when it gets to applicationDidFinishLaunching:it will appear to pause from the end users perspective because no view will appear to replace the default.png.
You should note that the standard launch time for an app is 3-5 seconds. So you may not have to do anything to show the splash screen for 3 seconds. It might happen automatically.
Apple strictly recommends against this (using sleep in this way), especially in the scenario of showing a splash screen.
The best thing to do is create a view that looks like your Default.png file, then have that be the first NIB.. you could then set an NSTimer to transition (with animation if you want) to your main view/window/controller.
Recently I've been looking to create some way of showing a user that something is being loaded. I'm sure anyone with an iPhone has seen this is apps before but what is the best way of doing it?
I started using UIProgressHUD, however it was pointed out to me that you shouldn't really use private (undocumented) API's.
I then I moved onto this which is a custom version called MBProgressHUD, however in my experience with this is wouldn't show the loading part when trying to call it not from a button and I found it very buggy (It wasn't very hard to crash the example code given by just clicking away).
I then went on to find this by James Brannan from his book, however I'm not quite sure why he claims this is the "proper way" of doing it when I've seen many apps in the past with what looks like the UIProgressHUD.
Does anyone have any ideas?
EDIT: This is pretty good...
Thanks
There is no one "best" way. Another way to do this is to simply put a UIView atop your main view's subviews, mark its userInteraction property and grey it out when needed. You could even add a UIActivityIndicator as a subview of this "foreground" UIView, starting its animation when needed. When your loading has finished, hide/stop the activity indicator and clear the foreground view's color.
If you are talking about loading over a network, one good thing to start with is to enable the status bar network activity indicator:
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
Note that you have to set it to NO when you are done! That should only be used to indicate network activity.
That's a bit subtle though, it's a great idea to have some kind of progress indicator IF you can tell exactly how long something is going to take - downloads where you know the size and count incoming bytes, or uploads where you also monitor bytes outgoing and know the total size.
If your call length is very small or the size is not really known (web service call is a great example) then some kind of overlay with a UIActivityIndicator can be very relaxing (you can also make a custom variant with a set of images added to a UIImage view to animate). The key is, that if possible it should not block the user from doing other things if possible.
Also if you have multiple things going on, you might want to add messages describing what state you are in (like, "adjusting image", "uploading image", etc).