diff --git a/baRSS/AppHook.m b/baRSS/AppHook.m
index 1df7263..3245049 100644
--- a/baRSS/AppHook.m
+++ b/baRSS/AppHook.m
@@ -30,6 +30,7 @@
#import "StoreCoordinator.h"
#import "SettingsFeeds+DragDrop.h"
#import "NSURL+Ext.h"
+#import "NSError+Ext.h"
@interface AppHook()
@property (strong) NSWindowController *prefWindow;
@@ -119,10 +120,8 @@
if (_persistentContainer == nil) {
_persistentContainer = [[NSPersistentContainer alloc] initWithName:@"DBv1"];
[_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
- if (error != nil) {
- NSLog(@"Couldn't read NSPersistentContainer: %@, %@", error, error.userInfo);
+ if ([error inCaseLog:"Couldn't read NSPersistentContainer"])
abort();
- }
}];
}
}
@@ -133,7 +132,7 @@
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
NSManagedObjectContext *context = self.persistentContainer.viewContext;
if (![context commitEditing]) {
- NSLog(@"%@:%@ unable to commit editing to terminate", [self class], NSStringFromSelector(_cmd));
+ NSLogCaller(@"unable to commit editing to terminate");
return NSTerminateCancel;
}
if (!context.hasChanges) {
diff --git a/baRSS/Core Data/NSFetchRequest+Ext.m b/baRSS/Core Data/NSFetchRequest+Ext.m
index 747cc62..6685268 100644
--- a/baRSS/Core Data/NSFetchRequest+Ext.m
+++ b/baRSS/Core Data/NSFetchRequest+Ext.m
@@ -21,6 +21,7 @@
// SOFTWARE.
#import "NSFetchRequest+Ext.h"
+#import "NSError+Ext.h"
@implementation NSFetchRequest (Ext)
@@ -28,7 +29,7 @@
- (NSArray*)fetchAllRows:(NSManagedObjectContext*)moc {
NSError *err;
NSArray *fetchResults = [moc executeFetchRequest:self error:&err];
- if (err) NSLog(@"ERROR: Fetch request failed: %@", err);
+ [err inCaseLog:"Fetch request failed"];
//NSLog(@"%@ ==> %@", self, fetchResults); // debugging
return fetchResults;
}
diff --git a/baRSS/Core Data/StoreCoordinator.m b/baRSS/Core Data/StoreCoordinator.m
index 795782b..06d8600 100644
--- a/baRSS/Core Data/StoreCoordinator.m
+++ b/baRSS/Core Data/StoreCoordinator.m
@@ -26,6 +26,7 @@
#import "FaviconDownload.h"
#import "Feed+Ext.h"
#import "NSURL+Ext.h"
+#import "NSError+Ext.h"
#import "NSFetchRequest+Ext.h"
@implementation StoreCoordinator
@@ -52,18 +53,13 @@
@param flag If @c YES save any parent context as well (recursive).
*/
+ (void)saveContext:(NSManagedObjectContext*)context andParent:(BOOL)flag {
- // Performs the save action for the application, which is to send the save: message to the application's managed object context. Any encountered errors are presented to the user.
- if (![context commitEditing]) {
- NSLog(@"%@:%@ unable to commit editing before saving", [self class], NSStringFromSelector(_cmd));
- }
+ if (![context commitEditing])
+ NSLogCaller(@"unable to commit editing before saving");
NSError *error = nil;
- if (context.hasChanges && ![context save:&error]) {
- // Customize this code block to include application-specific recovery steps.
- [NSApp presentError:error];
- }
- if (flag && context.parentContext) {
+ if (context.hasChanges && ![context save:&error])
+ [error inCasePresent:NSApp];
+ if (flag && context.parentContext)
[self saveContext:context.parentContext andParent:flag];
- }
}
@@ -284,7 +280,7 @@
bdr.resultType = NSBatchDeleteResultTypeCount;
NSError *err;
NSBatchDeleteResult *res = [moc executeRequest:bdr error:&err];
- if (err) NSLog(@"%@", err);
+ [err inCaseLog:"Couldn't delete batch"];
return [res.result unsignedIntegerValue];
}
diff --git a/baRSS/Feed Import/OpmlFile.m b/baRSS/Feed Import/OpmlFile.m
index 0caa832..54b6529 100644
--- a/baRSS/Feed Import/OpmlFile.m
+++ b/baRSS/Feed Import/OpmlFile.m
@@ -28,6 +28,7 @@
#import "Constants.h"
#import "NSDate+Ext.h"
#import "NSView+Ext.h"
+#import "NSError+Ext.h"
#pragma mark - Helper
@@ -98,9 +99,7 @@ static NSInteger RadioGroupSelection(NSView *view) {
RSXMLData *xml = [[RSXMLData alloc] initWithData:data url:url];
RSOPMLParser *parser = [RSOPMLParser parserWithXMLData:xml];
[parser parseAsync:^(RSOPMLItem * _Nullable doc, NSError * _Nullable error) {
- if (error) {
- [NSApp presentError:error];
- } else {
+ if (![error inCasePresent:NSApp]) {
for (RSOPMLItem *itm in doc.children) {
block(itm);
}
@@ -250,7 +249,7 @@ static NSInteger RadioGroupSelection(NSView *view) {
NSData *xml = [doc XMLDataWithOptions:NSXMLNodePreserveAttributeOrder | NSXMLNodePrettyPrint];
[xml writeToURL:url options:NSDataWritingAtomic error:&error];
}
- if (error) [NSApp presentError:error];
+ [error inCasePresent:NSApp];
return error;
}
diff --git a/baRSS/Info.plist b/baRSS/Info.plist
index b75b610..01fa3ec 100644
--- a/baRSS/Info.plist
+++ b/baRSS/Info.plist
@@ -70,7 +70,7 @@
CFBundleVersion
- 13404
+ 13435
LSApplicationCategoryType
public.app-category.news
LSMinimumSystemVersion
diff --git a/baRSS/NSCategories/NSError+Ext.h b/baRSS/NSCategories/NSError+Ext.h
index abe6cb7..7f8f282 100644
--- a/baRSS/NSCategories/NSError+Ext.h
+++ b/baRSS/NSCategories/NSError+Ext.h
@@ -22,9 +22,15 @@
@import Cocoa;
+/// Log error message and prepend calling class and calling method.
+#define NSLogCaller(desc) { NSLog(@"%@:%@ %@", [self class], NSStringFromSelector(_cmd), desc); }
+
@interface NSError (Ext)
// Generators
+ (instancetype)statusCode:(NSInteger)code reason:(nullable NSString*)reason;
+ (instancetype)canceledByUser;
+ (instancetype)feedURLNotFound:(NSURL*)url;
+// User notification
+- (BOOL)inCaseLog:(nullable const char*)title;
+- (BOOL)inCasePresent:(NSApplication*)app;
@end
diff --git a/baRSS/NSCategories/NSError+Ext.m b/baRSS/NSCategories/NSError+Ext.m
index 85ca6ed..31f7b40 100644
--- a/baRSS/NSCategories/NSError+Ext.m
+++ b/baRSS/NSCategories/NSError+Ext.m
@@ -126,4 +126,21 @@ static const char* CodeDescription(NSInteger code) {
return RSXMLMakeErrorWrongParser(RSXMLErrorExpectingFeed, RSXMLErrorExpectingHTML, url);
}
+// ---------------------------------------------------------------
+// | MARK: - User notification
+// ---------------------------------------------------------------
+
+/// Will only execute and return @c YES if @c error @c != @c nil . Log error message to console.
+- (BOOL)inCaseLog:(nullable const char*)title {
+ if (title) printf("ERROR %s: %s, %s\n", title, self.description.UTF8String, self.userInfo.description.UTF8String);
+ else printf("%s, %s\n", self.description.UTF8String, self.userInfo.description.UTF8String);
+ return YES;
+}
+
+/// Will only execute and return @c YES if @c error @c != @c nil . Present application modal error message.
+- (BOOL)inCasePresent:(NSApplication*)app {
+ [app presentError:self];
+ return YES;
+}
+
@end
diff --git a/baRSS/NSCategories/NSURL+Ext.m b/baRSS/NSCategories/NSURL+Ext.m
index 243756a..5647616 100644
--- a/baRSS/NSCategories/NSURL+Ext.m
+++ b/baRSS/NSCategories/NSURL+Ext.m
@@ -22,6 +22,7 @@
#import "NSURL+Ext.h"
#import "UserPrefs.h" // appName in +faviconsCacheURL
+#import "NSError+Ext.h"
@implementation NSURL (Ext)
@@ -50,9 +51,8 @@
- (BOOL)mkdir {
if ([self existsAndIsDir:YES]) return NO;
NSError *err;
- BOOL b = [[NSFileManager defaultManager] createDirectoryAtURL:self withIntermediateDirectories:YES attributes:nil error:&err];
- if (err) [NSApp presentError:err];
- return b;
+ [[NSFileManager defaultManager] createDirectoryAtURL:self withIntermediateDirectories:YES attributes:nil error:&err];
+ return ![err inCasePresent:NSApp];
}
/// Delete file or folder at URL. If item does not exist, this method does nothing.
diff --git a/baRSS/Preferences/Feeds Tab/SettingsFeeds.m b/baRSS/Preferences/Feeds Tab/SettingsFeeds.m
index ab72b99..753c475 100644
--- a/baRSS/Preferences/Feeds Tab/SettingsFeeds.m
+++ b/baRSS/Preferences/Feeds Tab/SettingsFeeds.m
@@ -27,6 +27,7 @@
#import "FeedGroup+Ext.h"
#import "UpdateScheduler.h"
#import "SettingsFeedsView.h"
+#import "NSError+Ext.h"
@interface SettingsFeeds ()
@property (strong) SettingsFeedsView *view; // override super
@@ -100,7 +101,7 @@
NSError *error;
[self.dataStore fetchWithRequest:nil merge:NO error:&error];
- if (error) [NSApp presentError:error];
+ [error inCasePresent:NSApp];
}
/**