This may be of little use to anyone, but it's possible to return from UIApplicationMain by nesting the call in a try{}catch(NSException* e){} block. I'm currently doing this for testing my setup process, in order to run some logic after the application exits. I'd like to take this a step further and actually write separate UIApplication sub classes and run them in serial but UIApplicationMain doesn't want to play nice, it's a singleton and it must remember what it once was (the first UIApplication to be instantiated). Here's the error I get when I attempt to create a second UIApplication after returning from the first call to UIApplicationMain...
2010-12-28 16:01:36.890 SomeFakeAppName[26993:207] *** Assertion failure in UIApplicationInstantiateSingleton(), /SourceCache/UIKit_Sim/UIKit-1447.6.4/UIApplication.m:1263
So, two questions:
I understand that I'm probably 'Doing It Wrong' but how might I go about clearing UIApplication's memory so that it thinks each successive UIApplication instantiation is its first?
If this is a dead end I may try replacing UIApplicationMain by manually setting up the main event loop and instantiating the UIApplication, has anyone done this?
Pretty sure you can't. UIApplication's are managed on the OS level and Apple doesn't really give you the keys to drive how all that works.
If it's possible at all, you would be diving into private APIs (which shouldn't be a problem cause we are talking about non-released test suite setup right?). Look up the UIApplication.h decompiled header files that are in a few various places. Look for private methods that sounds like what you want and try it out.
But in all likelihood, this path leads leads to pain and suffering.
Related
I am calling a monitoring task via thread using the following code which is called from the viewDidLoad() in a ViewController:
let myDaemon = Thread(target: self.myMonitor, selector:#selector(self.myMonitor), object: nil)
myDaemon.start()
I have been unable to find a way to find and cancel that thread without closing the app. Is there maybe an alternate way to launch the thread so I can cancel it if needed?
I thought about creating an observer so I could cancel it from another VC but since the Daemon is initialized in the viewDidLoad, I can't access it outside of that block.
I'm using Swift 5. Any suggestions are appreciated.
Thanks,
First, you should almost never use Thread in Swift. Directly accessing threads has been discouraged in Cocoa since longer than Swift has been a language. You should generally be using, in order of preference for the kinds of problems threads are usually used for, async/await (possibly plus an AsyncChannel), OperationQueues, or DispatchQueues. That said, it's a fine question, and there are still very rare cases where a Thread would be appropriate, or at least useful.
To cancel a thread, you will either need to keep track of it (the returned value) so you can call .cancel(), or you need to have a way to communicate with the thread (a Pipe for example) so that you can send a custom "stop" message. That means storing that returned value (or the communication mechanism) somewhere outside the VC.
A ViewController should not own a global object like a Thread. ViewControllers come and go. You should move your thread management (if you're going to do thread management, which you generally shouldn't) into a model object that the VCs share.
Note that canceling a thread does not cause a thread to stop running. The only thing it does is set the isCancelled flag. If is still up to your thread to periodically check itself for cancellation and stop. (You may already know this, but it's a very common confusion, so I want to make sure anyone reading this later is aware.)
There is no list of all existing threads for you to search (and that would be pretty obnoxious since the frameworks generate quite a lot of threads you would need to crawl through). If you want to keep track of a thread, you need to store it somewhere.
The last sentence of the Apple Documentation for ARSession.run(_:options) in the the discussion section states:
ARSession.run(_:options)https://developer.apple.com/documentation/arkit/arsession/2875735-run?changes=latest_minor
”After you call this method, the session runs asynchronously.”
What do this mean?
Does it mean it runs on a different thread from the main forever?
Or
Does it mean that while it is transitioning from the previous session to new session it will be rerunning on a different thread?
Or
Does it mean something else?
I really want like to know/understand and would really appreciate any kind soul out there who would like to give some insight:-)
Thank you to the kind ARKit community,
We all learn by sharing what we know
Smartdog
“(A)synchronous” doesn’t have to mean multithreaded.
I’m pretty sure all they mean by that is:
the run(_:options:) call returns immediately
the session is an ongoing process (at least partly in the main run loop, since it has per-frame callbacks, but possibly also involving other threads you don’t see)
This would be in contrast calls that are “synchronous” meaning that all effects of the call complete before it returns.
In my app requirement is, when the app is launch for the first time it will send request to server to get data, parse it and save it in document folder which will be used across entire project.Again after particular time interval the app will send request to server to get updated data(if any) and update that data in document folder, which again will be updated across entire project.All this process is happening in background thread.This process will repeat until the app is running in foreground once the user close the app, the app will get terminate, it will not go in background.
This repeated request I am creating in app delegate as well as doing xml parsing once the data is received and saving after parsing. Now my question is, Is this proper means doing too much stuff in app delegate is safe or there is some limitation or is this bad programming?
What is the correct way of doing this?
I disagree with torrey.lyons to an extent. I think creating singletons is bad practice generally speaking and should be avoided where possible. One thing you should never do is code a class so that it has to be a singleton. Purpose built singletons tend to increase coupling and can be really problematic when it comes to unit testing where you might want to replace your singleton with a stub class or you might need it to be reinitialised for each unit test.
If this task of getting data is an application level task, there is absolutely no reason why it can't logically be located in the application delegate. I would however create a "connection manager" as torrey.lyons suggests and have one as a property of the app delegate.
I would also not use an explicit background thread to do the data update but I would use a subclass of NSOperation. This is a whole lot easier than managing your own thread.
It is bad practice. Your app delegate should ideally be concerned purely with its own responsibilities, i.e.. responding to the messages the application sends its delegate. It is much better to split off other discrete responsibilities into other objects. For example, you could have a "connection manager" object that is responsible for periodically communicating with the server. If you are sure the app will only connect to one server at a time you probably want to use the singleton pattern so that there only one instance of the object in your application and it can be easily reached by any other class. A good discussion of the proper role of the app delegate and singletons can be found on at Singletons, AppDelegates and top-level data. A good general overview on writing singletons can be found under the Care and Feeding of Singletons.
First of all, I am a a very new Objective C/Cocoa iOS Developer but I've written C/C++ applications before.
So I managed to run the Rabbitmq-c (http://hg.rabbitmq.com/rabbitmq-c/) client inside my iPhone App, and I can connect to Rabbitmq directly from my app and even consume a queue item. So all's good.
Now my problem is, my iPhone app needs to use the rabbitmq-c library to poll for incoming messages in from the server. Probably there will be, an almost infinite while loop.
Do I have to take this to a new thread? Ideally, I want to wrap the rabbitmq-c class as an Async objective C class and use NSNotification (or something similar) to notify my UI. I'm a bit leery of creating a new thread, as I read about stuffs like Runloop etc can solve a lot of problems without using an extra thread.
What is the best way for me to go about this? Any examples of code or directions would be helpful. Please remember, I am not dealing with an Objective C code/Coca rabbitmq library here, I'm using C code inside my iPhone app.
Thanks
Subrat
don't block the main thread with your server polling.
since the operation never ends, create your own thread and run loop for this server polling. you can potentially use the run loop (each thread has one) instead of the infinite while. the alternatives involve regularly spawning threads. it's easiest to just use one thread for this.
once you have an update, post the notification (if you choose NSNotification) from the main thread -- UIKit is meant to operate from the main thread only.
for samples, i'd begin with samples related to NSRunLoop and CFRunLoop.
good luck
You can also create custom delegates for updating the UI, or the stuff related to UIKit.
Notifications might be a little easier to code and offer the advantage that multiple objects can observe one notification. With delegates, such a thing cannot be done without modifying the delegating object (and is unusual).
Some advantages of delegating:
The connection between delegating object and delegate is made clearer, especially if implementing the delegate is mandatory.
If more than one type of message has to be passed from delegatee to delegate, delegating can make this clearer by specifying one delegate method per message.
Or other way is to write method to receive messages. This method can have infinite loop.
Later you can put this method in background thread like this.
[self performSelectorInBackground:#selector(receiveMessages) withObject:nil];
I'm trying to port a game library over to the iPhone. Unlike SDL, this library doesn't take full control of your main() function, it's communicated with via quickly-returning functions from your own code. So, for example, obvious pseudocode:
int main() {
library_init();
// game init code here
while(we_have_not_quit_the_game) {
library_message_loop();
library_init_render();
// render stuff
library_end_render();
// update game state
}
library_shutdown();
}
iPhone makes this difficult, as it requires that you call a UIApplicationMain function that never returns. There's simply no way I could ever get back to the user code after library_init();.
I'm not convinced it's necessary - there's NSRunLoop which supposedly could be used to handle the events. I don't know if UIApplicationMain does anything else of importance, however. (Note that I have no plans to use .nib files, which is the only other thing I've found that UIApplicationMain does.)
I've got three real ideas that I can think of, but they're all a major implementation effort so I'd like to know if anyone has experience with this before I burn a day trying doomed ideas.
In Init, spawn a new thread, run UIApplicationMain in that thread. Either communicate all events across threads (ugh) or just put the UIApplicationMain thread to sleep and use a CFRunLoop in the main thread. I've heard UIApplicationMain does not like being run in a different thread, however.
Ignore UIApplicationMain entirely, just use NSRunLoop. Am I going to be missing important iPhone setup? Who knows!
Do something horrifying with longjmp() to leap out of the UIApplicationMain code after setup, pray that it doesn't do anything important during teardown.
Suggestions?
Looks like I'm answering my own question here! I'm not accepting my answer until I've been able to both test it on real hardware and get it into the app store. That said, I'll keep my Most Up-To-Date Info here, including which options didn't work.
Idea #1: It turns out that each NSRunLoop is thread-specific. If I create a UIApplicationMain in a separate thread, it doesn't get any messages. As a side effect this makes it impossible to determine when it's finished initializing, so if there's anything non-threadsafe it does, it just won't work. I may be able to send it a message across threads to figure out when it's finished initializing, but for now I'm calling this a dead end.
Idea #2: UIApplicationMain does a lot of subtle stuff. I'm not sure what it's restricted to, but I was unable to make anything work without involving UIApplicationMain. Idea #2 is right out.
Idea #3: Receiving the OS signals is important - you need to know if there's a phone-call overlay, or whether you're about to exit. On top of that, some of the setup messages seem vital in order to start the app properly. I was unable to find any method to keep messages being sent without being inside UIApplicationMain. The only options I came up with were NSRunLoop and CFRunLoop. Neither one worked - the messages didn't come in like I wanted. I may not be using these right, but in any case, Idea #3 is out.
Brand-new crazy Idea #4: It's possible to use setjmp/longjmp to fake coroutines in C/C++. The trick is to first set the stack pointer to some value that won't clobber anything important, then start your second routine, then jump back and forth, pretending like you have two stacks. Things get a tiny bit messy if your "second coroutine" decides to return from its main function, but luckily, UIApplicationMain never returns, so this isn't a problem.
I don't know if there's a way to set the stack pointer explicitly on real hardware, say, to a chunk of data that I allocated on the fly. Luckily, it doesn't matter. The iPhone has a 1MB stack by default, which is easily enough to fit a few coroutines in.
What I'm currently doing is using alloca() to push the stack pointer ahead by 768 kilobytes, then spawning UIApplicationMain, then using setjmp/longjmp to bounce back and forth between my "UI routine" and my "main routine". So far, this is working.
Caveats:
It's impossible to know when the "UI routine" has no messages to handle, and when it has no messages to handle, it will just block indefinitely until that's no longer the case. I'm solving this by making a timer that triggers every 0.1 milliseconds. Every time the timer triggers, I drop out to my "main routine", do a single game loop, then head back into the "UI routine" for another timer tick. Reading the documentation indicates that it won't stack up "timer calls" indefinitely. I do seem to get the "terminate" message appropriately, though I haven't managed to test it thoroughly yet, and I haven't tested any other important messages. (Luckily, there's only four messages total, and one of them is setup-related.)
Most modern OSes won't allocate the entire stack at once. The iPhone is probably one of these. What I don't know is whether bumping the stack pointer 3/4 of a meg forward will allocate everything "behind it", so to speak. If so, I may be effectively wasting 3/4 of a meg of RAM, which, on the iPhone, is significant. This could be handled by bumping the pointer forward a smaller amount, but this is really courting stack size disaster - it effectively limits your stack to however far you bump the pointer ahead, and you'll have to figure this out in advance. Some sentinel data in the stack, coupled with good monitoring and a logging system for stack size issues, can probably solve this, but it's a nontrivial issue. (Alternatively, if I can figure out how to muck with the stack pointer directly on the native hardware, I can just malloc()/new[] a few kilobytes, point the stack pointer at it, and use it as my new stack. I'll have to figure out how much space it needs but I doubt it'll be much, considering that it's not doing very much.)
This is currently untested on the actual hardware (give it a week or two, I got another project to finish first.)
I have no idea whether Apple will figure out what I'm doing and slap a giant REJECTED sticker on it when I try submitting to the app store. This is, shall we say, slightly outside their intentions for the API. Fingers crossed.
I'll keep this post updated, and officially accept it once I've verified that it, you know, works.
Late update: I got distracted by a variety of other things. Since then, I've had a few changes that make me far less interested in Apple development. My current approach showed no sign of not working, but I don't really have the motivation to keep fleshing it out. Sorry! If I ever change my mind I'll update this further, but Outlook Not So Good.
I know NSApplicationMain() reads Info.plist and does stuff to the app (like get the initial nib file) so I would guess that UIApplicationMain() does the same for iPhone (like get the initial status bar style, zoom the default.png image in etc.). That stuff isn't exposed anywhere else, so the functions it calls would still need to be run for the app to launch with out any side effects. You're only bet is to reverse engineer those and copy them (and hope that anything they do is in the public SDK).
Is the goal to take that main() function and have it work unmodified on the iPhone?
It would seem there's no way you're going to completely insulate the users of the library from thinking about the iPhone platform--they're going to have to deal with XCode for code signing and that sort of thing.
Given that, telling users they have to break their main() function up into a few pieces that you can call from applicationDidFinishLaunching and from an appropriate timer doesn't seem like it would inconvenience anybody much.
Why not start your game loop from within UIApplication? (Yes, you can't have it in main() but that shouldn't matter.) Some of the delegate messages are good candidates.