There are two ways to capture application transitioning to foregorund/background and inactive/active. Lets take the event received when app transitions to the inactive state as an example.
Implement the corresponding AppDelegate method - applicationWillResignActive(_:)
func applicationWillResignActive(_ application: UIApplication) {
Log("applciationWillResignActive(_:)")
}
Register for willResignActiveNotification during startup
NotificationCenter.default.addObserver(forName:UIApplication.willResignActiveNotification, object: nil, queue: .main) { (broadcastNotification: Notification) in
Log("Received " + String(describing: broadcastNotification.name))
}
When I tested in code, both works. First, the applicationWillResignActive(_:) delegate method is invoked and then, willResignActiveNotification is received (as mentioned in the documentation).
But I'm unable to decide which to use... even after reading their documentation. What is the recommendation? If both are fine, then there are two different ways to achieve the same thing... there's gotta be some purpose, right?
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
In an iOS project, I have implemented the following delegate method to handle Notifications when app is in foregorund:
func userNotificationCenter (_ pNotificationCenter : UNUserNotificationCenter, willPresent pNotification : UNNotification, withCompletionHandler pCompletionHandler : @escaping (UNNotificationPresentationOptions) -> Void) -> Void
{
// When app is in foreground, notification is directly sent to
// the app by invoking this delegate method.
}
When building, I'm getting the warning. But my implementation is correct according to documentation.
Why is this method not recognized as the implementation of the UNUserNotificationCenterDelegate protocol?
This is the warning in text format:
Showing All Issues
<file path & line number>: Instance method 'userNotificationCenter(_:willPresent:withCompletionHandler:)' nearly matches optional requirement 'userNotificationCenter(_:willPresent:withCompletionHandler:)' of protocol 'UNUserNotificationCenterDelegate'
This is the image of the warning:
Am I missing some flag in a compiler setting?
My env:
Xcode 15.2, Swift 5.0, Deployment target - iOS 14.0+.
I have an iOS app which uses Notification Service Extension (NSE) to process incoming notifications before it displayed to user.
In NSE, as part of initialization of my app, I need to iterate through a 2D array. There are roughly 65k iterations. I've noticed that this iteration fails somewhere in between and the NSE process crashes... I can say it crashes because the logs stopped in between the iterations. This results in 'unmodified notification' getting displayed immediately, whereas NSE is granted 30 sec of background execution.
My question is, why does this happen? The above iteration of 2D array works in app, but fails in NSE. Is there some kind of restriction on background extensions? - the documentation only talks about a time limit of 30sec. If there is some kind of restriction (like CPU and memory), how does one know this and code for it... since Apple did not provide any documentation. Or perhaps, there is a completely different reason?
I have an app whose logic is in C++ and rest of the parts (UI) are in Swift and SwiftUI.
When an exception is raised by some C++ code, I'm using the Linux signal handler mechanism to trap it. From my previous post, I understand that fatal exceptions like SIGSEGV, SIGBUS, SIGFPE etc., there's nothing much that can be done by the process. My only intent for using a signal handler is to log something, so that it becomes easy to fix during development. Ofc, even that logging can fail, based on the severity of the exception, but that's okay... make an attempt to log - if it works, great, else the process can terminate.
I'm registering for SIGSEGV and SIGFPE with the following code
// ExceptionHandlingCpp.hpp file
struct tSignals {
SignalHandlerFunc signalHandlerFunc;
uint32_t signal;
[[maybe_unused]]
uint8_t reserved[4];
};
// ExceptionHandlingCpp.cpp file
tSignals ExceptionHandlingCpp::unixSignals[] = {
{HandleSignals, SIGFPE, {0}},
{HandleSignals, SIGSEGV, {0}},
{HandleSignals, SIGKILL, {0}},
};
std::string ExceptionHandlingCpp::signalToString(int signal) {
switch(signal) {
case SIGFPE:
return "SIGFPE";
case SIGSEGV:
return "SIGSEGV";
case SIGKILL:
return "SIGKILL";
default:
return "Unknown signal";
}
}
void ExceptionHandlingCpp::RegisterSignals() {
LOG("ExceptionHandlingCpp::RegisterSignals()");
struct sigaction sa;
sa.sa_flags = SA_SIGINFO;
for(int i = 0; i < sizeof(unixSignals)/sizeof(tSignals); ++i) {
sa.sa_sigaction = unixSignals[i].signalHandlerFunc;
if(sigaction(unixSignals[i].signal, &sa, nullptr) == 1) {
LOG("Failed to set " + signalToString(unixSignals[i].signal) + "'s signal handler!");
} else {
LOG(signalToString(unixSignals[i].signal) + "'s signal handler set sucessfully!");
}
}
}
In my signal handler (HandleSignals method), immediately after trapping a signal, I log something and set the default handler... This breaks out of the loop that occurs when returning from the signal handler.
// ExceptionHandlingCpp.cpp
void ExceptionHandlingCpp::HandleSignals(int pSignal, siginfo_t *pInfo, void *pContext) {
LOG("ExceptionHandlingCpp::HandleSignals(int, signinfo_t*, void*)");
LOG("signal = " + signalToString(pSignal));
UnregisterSignals(pSignal);
LOG("Returning from exception handler...");
}
void ExceptionHandlingCpp::UnregisterSignals(int pSignal) {
LOG("UnregisterSignals(int)");
struct sigaction defaultAction {};
defaultAction.sa_handler = SIG_DFL;
if(sigaction(pSignal, &defaultAction, nullptr) == -1) {
LOG("Error in resetting action for " + signalToString(pSignal));
} else {
LOG("Successfully reset " + signalToString(pSignal) + "'s action to default!");
}
}
When I test this code by raising SIGSEGV (as shown below),
void ExceptionHandlingCpp::DereferenceNullPtr ()
{
LOG("DereferenceNullPtr()");
int* ptr = nullptr;
LOG("Raising exception...");
int value = *ptr;
}
everything works as expected. Signal handler is invoked, default handler is set and the process immediately quits. But when I try to raise a SIGFPE,
void* ExceptionHandlingCpp::DivisionByZero ([[maybe_unused]] void* pParms)
{
LOG("DivisionByZero()");
int num1;
int num2;
int result;
num1 = 5;
num2 = 0;
LOG("Raising exception...");
result = num1 / num2;
LOG("Returning from DivisionByZero() method");
return nullptr;
}
my signal handler is not invoked (as shown in the logs below). The process doesn't terminate either. It seems that the flow simply 'walks over' this division by zero instruction as if nothing happened and returns from that method, which shouldn't have happened, as the process should've terminated after reaching my signal handler.
RegisterSignals()
SIGFPE's signal handler set sucessfully!
SIGSEGV's signal handler set sucessfully!
SIGKILL's signal handler set sucessfully!
....
DivisionByZero()
Raising exception...
Returning from DivisionByZero() method
....
AppDelegate.applicationWillBecomeActive(_:)
AppDelegate.applicationDidBecomeActive(_:)
...
// UI is displayed
Why is SIGFPE not raised? What am I missing here?
I have an app whose logic is in C++ and rest of the parts (UI) are in Swift and SwiftUI.
Exceptions can occur in C++ and Swift. I've got the C++ part covered by using the Linux's signal handler mechanism to trap signals which get raised due to exceptions.
But how should I capture exceptions in Swift? When I say exceptions in Swift, I mean, divide by zero, force unwrapping of an optional containing nil, out of index access in an array, etc. Basically, anything that can go wrong, I don't want my app to abruptly crash... I need a chance to finalise my stuff, alert the user, prepare diagnostic reports and terminate. I'm looking for a 'catch-all' exception handler. As an example, let's take Android. In Android, there is the setDefaultUncaughtExceptionHandler method to register for all kinds of exceptions in any thread in Kotlin. I'm looking for something similar in Swift that should work for macOS, iOS & iPadOS, tvOS and watchOS.
I first came across the NSSetUncaughtExceptionHandler method. My understanding is, this only works when I explicitly raise NSExceptions. When I tested it, observed that the exception handler didn't get invoked for either case - divide by zero or invoking raise.
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
Log("AppDelegate.applicationDidFinishLaunching(_:)")
// Set the 'catch-all' exception handler for Swift exceptions.
Log("Registering exception handler using NSSetUncaughtExceptionHandler()...")
NSSetUncaughtExceptionHandler { (exception: NSException) in
Log("AppDelegate.NSUncaughtExceptionHandler()")
Log("Exception: \(exception)")
}
Log("Registering exception handler using NSSetUncaughtExceptionHandler() succeeded!")
// For C++, use the Linux's signal mechanism.
ExceptionHandlingCpp.RegisterSignals()
//ExceptionHandlingCpp.TestExceptionHandler()
AppDelegate.TestExceptionHandlerSwift()
}
static func TestExceptionHandlerSwift() {
Log("AppDelegate.TestExceptionHandlerSwift()")
DivisionByZero(0)
}
private static func DivisionByZero(_ divisor: Int) {
Log("AppDelegate.DivisionByZero()")
let num1: Int = 2
Log("Raising Exception...")
//let result: Int = num1/divisor
let exception: NSException = NSException(name: NSExceptionName(rawValue: "arbitrary"), reason: "arbitrary reason", userInfo: nil)
exception.raise()
Log("Returning from DivisionByZero()")
}
}
In the above code, dividing by zero, nor raising a NSException invokes the closure passed to NSSetUncaughtExceptionHandler, evident from the following output logs
AppDelegate.applicationWillFinishLaunching(_:)
AppDelegate.applicationDidFinishLaunching(_:)
Registering exception handler using NSSetUncaughtExceptionHandler()...
Registering exception handler using NSSetUncaughtExceptionHandler() succeeded!
ExceptionHandlingCpp::RegisterSignals()
....
AppDelegate.TestExceptionHandlerSwift()
AppDelegate.DivisionByZero()
Raising Exception...
Currently, I'm reading about ExceptionHandling framework, but this is valid only for macOS.
What is the recommended way to capture runtime issues in Swift?
I have created a sample app which read/write from a network file. When the file was attempted to open (using open Linux API), connection to network file was lost. The thread which was stuck on the open method, returns after a long time.
It was observed that for macOS, the maximum return time of the thread was around 10 mins, whereas in Windows and Linux, the maximum timeout was 60 sec and 90 sec.
macOS has a very large timeout before returning the thread with a network failure error. Is this by designed and expected? With a large timeout as 10mins, it's difficult to respond swiftly back to the user.