How can I know where exactly did my app crash ?
I receive a lot of crash from my users but I can't reproduce the crash myself and the crash log does not indicate a specific line:
Thread : Crashed: com.apple.main-thread
0 myapp 0x22d1d4 specialized ItemType.init(coder : NSCoder) -> ItemType? (ItemType.swift)
1 myapp 0x22c72c #objc ItemType.init(coder : NSCoder) -> ItemType? (ItemType.swift)
2 EventKitUI 0x234734a5 (Missing)
3 EventKitUI 0x23479639 (Missing)
4 EventKitUI 0x234161db (Missing)
5 EventKitUI 0x234734a5 (Missing)
6 EventKitUI 0x234728d3 (Missing)
7 myapp 0x1e9df4 specialized Item.init(coder : NSCoder) -> Item? (Item.swift:162)
8 myapp 0x1db9b8 #objc Item.init(coder : NSCoder) -> Item? (Item.swift)
9 EventKitUI 0x234734a5 (Missing)
10 EventKitUI 0x234728d3 (Missing)
11 EventKitUI 0x23471bc7 (Missing)
12 myapp 0x26f370 savedSearchList.getLastItem() -> Item! (savedItemList.swift:71)
13 myapp 0x26c008 specialized MenuInitializerViewController.getSideMenuViewController() -> UIViewController (MenuInitializerViewController.swift:39)
14 myapp 0x18388c SharedAppDelegate.showMainInterface() -> () (SharedAppDelegate.swift:427)
15 myapp 0x18398c #objc SharedAppDelegate.showMainInterface() -> () (SharedAppDelegate.swift)
16 myapp 0x188a48 SharedAppDelegate.(retreiveFirstData(SharedAppDelegate) -> () -> ()).(closure #1) (SharedAppDelegate.swift:290)
17 myapp 0x2657a4 partial apply for UserAppData.(getFirstData(UserAppData) -> (() -> (), failure : (error : NSError) -> ()) -> ()).(closure #3) (UserAppData.swift:45)
18 myapp 0x263828 partial apply for thunk (UserAppData.swift)
19 myapp 0x268c28 UserAppData.(getDiffusionsGroup(UserAppData) -> (() -> (), failure : (error : NSError) -> ()) -> ()).(successBlock #1)(AFHTTPRequestOperation!, responseObject : AnyObject!)() (UserAppData.swift:788)
20 myapp 0x266684 partial apply for UserAppData.(getDiffusionsGroup(UserAppData) -> (() -> (), failure : (error : NSError) -> ()) -> ()).(successBlock #1)(AFHTTPRequestOperation!, responseObject : AnyObject!)() (UserAppData.swift)
21 libtzupdate.dylib 0x344ffe2f (Missing)
22 libtzupdate.dylib 0x344ffe1b (Missing)
23 libtzupdate.dylib 0x345046c9 (Missing)
24 CoreAudio 0x226dc535 (Missing)
25 CoreAudio 0x226daa2f (Missing)
26 CoreAudio 0x2262d0d9 (Missing)
27 CoreAudio 0x2262cecd (Missing)
28 GeoServices 0x2b9a2af9 (Missing)
29 UIKit 0x268b62dd UIApplicationMain + 144
30 myapp 0x10f2d4 main (AppDelegate.swift:16)
31 libtzupdate.dylib 0x34528873 (Missing)
I understand that it might come from ItemType unarchive initializer, but I don't see what could be wrong with it:
required convenience init?(coder aDecoder: NSCoder)
{
self.index = aDecoder.decodeIntegerForKey("index")
self.name = aDecoder.decodeObjectForKey("name") as! String
self.id = aDecoder.decodeObjectForKey("id") as! String
self.type = Type(rawValue: aDecoder.decodeIntegerForKey("type")) ?? .Default
}
Try adding a Exception breakpoint and/or Swift error breakpoint in
View->Navigator->Show Breakpoint Navigator
and then click the + icon on the bottom
I am not sure this is helping but these two lines are not very safe code
self.name = aDecoder.decodeObjectForKey("name") as! String
self.id = aDecoder.decodeObjectForKey("id") as! String
You are force casting the object as a String without checking if it has a value. ObjectsForKeys are nil by default until you set them the first time.
So these 2 lines can potentially cause a crash if you haven't set the object at least once. Try using the ?? nil coalescing operator to ensure this cannot happen.
self.name = aDecoder.decodeObjectForKey("name") as? String ?? self.name
self.id = aDecoder.decodeObjectForKey("id") as? String ?? self.id
Now you check if the object exits (as? String) and if it doesnt than it uses the default name/id (?? self.name)
I am not sure this is causing the crash but this should improve your code.
Your code to save the Enum seems alrite because you are using the ?? operator, so I dont think thats causing the issue.
You only need to do nil checks for ObjectsForKeys, because they are of type AnyObject and therefore dont know what object they actually are until set once, hence it could cause a nil crash.
Compare this to say BoolForKey where you dont have to do this because it knows you are dealing with boolean values and therefore it defaults to false automatically.
Also, you are doing the same thing I keep seeing here, which is not using constants for keys. This is just prone to typos.
Create a struct above your class
struct Key {
static let name = "Name"
static let id = "ID"
}
and than use the keys like so
...objectForKey(Key.name)
Hope this helps
Related
My iOS app uses RealmSwift, and it is crashing during migration from an older version of the app. The error is: RLMException: Invalid Property Name <name> for class <class>.
The crash seems to be happening because of the following sequence of migrations:
Initial: Created a model (lets call it Story)
class Story: Object, Mappable {
#objc dynamic var _id = ""
#objc dynamic var lastModified: Date?
#objc dynamic var name = ""
#objc dynamic var content = ""
override static func primaryKey() -> String? {
return ServerKey.id
}
override static func indexedProperties() -> [String] {
return ["name"]
}
}
Migration X: Created another model using migration.create (lets call it Book) which contains the model created in the previous step (Book contains Story)
private class func migrateToVersionX(_ migration: Migration) {
migration.enumerateObjects( <perform unrelated migration to change some values on story objects> )
migration.create("Book", value: ["stories": <array containing stories>])
}
Migration X+2: Added a new field to Story (Story.author)
class Story: Object, Mappable {
#objc dynamic var _id = ""
#objc dynamic var lastModified: Date?
#objc dynamic var name = ""
#objc dynamic var content = ""
#objc dynamic var author = ""
override static func primaryKey() -> String? {
return ServerKey.id
}
override static func indexedProperties() -> [String] {
return ["name", "author"]
}
}
When a user has a version older than MigrationX, the app crashes with the following error (modified for this example)
'RLMException', reason: 'Invalid property name 'author' for class 'Story'.'
The app crashes at the migration.create call. This is the stack trace
Fatal Exception: RLMException
Invalid property name 'author' for class 'Story'.
0 CoreFoundation
__exceptionPreprocess
1 libobjc.A.dylib
objc_exception_throw
2 Realm
RLMAccessor.mm line 567
RLMDynamicGetByName
3 RealmSwift
Object.swift line 362
DynamicObject.subscript.getter
4 RealmSwift
<compiler-generated> line 0
#objc DynamicObject.value(forUndefinedKey:)
5 Foundation
-[NSObject(NSKeyValueCoding) valueForKey:]
6 Realm
RLMObjectBase.mm line 174
-[RLMObjectBase valueForKey:]
7 Realm
RLMObjectBase.mm line 451
RLMValidatedValueForProperty
8 Realm
RLMAccessor.mm line 633
RLMAccessorContext::propertyValue(objc_object*, unsigned long, RLMProperty*)
9 Realm
RLMAccessor.mm line 776
RLMAccessorContext::value_for_property(objc_object*,
std::__1::basic_string<char, std::__1::char_traits<char>,
std::__1::allocator<char> > const&, unsigned long)
10 Realm
object_accessor.hpp line 267
realm::Object realm::Object::create<objc_object* __strong, RLMAccessorContext>(RLMAccessorContext&, std::__1::shared_ptr<realm::Realm> const&, realm::ObjectSchema const&, objc_object* __strong, bool, realm::BasicRow<realm::Table>*)
11 Realm
row.hpp line 759
RLMCreateObjectInRealmWithValue
12 Realm
RLMAccessor.mm line 752
realm::BasicRowExpr<realm::Table> RLMAccessorContext::unbox<realm::BasicRowExpr<realm::Table> >(objc_object*, bool, bool)
13 Realm
list.hpp line 192
auto realm::List::dispatch<void realm::List::add<objc_object* __strong&, RLMAccessorContext>(RLMAccessorContext&, objc_object* __strong&&&, bool)::'lambda'(objc_object* __strong&)>(objc_object* __strong&&&) const
14 Realm
RLMAccessor.hpp line 77
void RLMAccessorContext::enumerate_list<void realm::List::assign<objc_object* __strong&, RLMAccessorContext>(RLMAccessorContext&, objc_object* __strong&&&, bool)::'lambda'(objc_object* __strong&&&)>(objc_object*, objc_object* __strong&&&)
15 Realm
list.hpp line 220
void realm::List::assign<objc_object* __strong&, RLMAccessorContext> (RLMAccessorContext&, objc_object* __strong&&&, bool)
16 Realm
object_accessor.hpp line 94
void realm::Object::set_property_value_impl<objc_object* __strong, RLMAccessorContext>(RLMAccessorContext&, realm::Property const&, objc_object* __strong, bool, bool)
17 Realm
object_accessor.hpp line 281
realm::Object realm::Object::create<objc_object* __strong, RLMAccessorContext>(RLMAccessorContext&, std::__1::shared_ptr<realm::Realm> const&, realm::ObjectSchema const&, objc_object* __strong, bool, realm::BasicRow<realm::Table>*)
18 Realm
row.hpp line 759
RLMCreateObjectInRealmWithValue
19 Realm
RLMRealm.mm line 840
-[RLMRealm createObject:withValue:]
20 Realm
RLMMigration.mm line 135
-[RLMMigration createObject:withValue:]
21 RealmSwift
Migration.swift line 129
Migration.create(_:value:)
22 Project Name
MigrationHelper.swift line 187
specialized static MigrationHelper.migrateToVersionX(_:)
I think what is happening is that the migration.create function in MigrationX is looking at the Story class and finding the author field, even though it formally isn't introduced until MigrationX+2.
Any thoughts on why this crash is happening and how to appropriately handle this scenario would be greatly appreciated.
There is a crash registered on Fabric in my app when I am fetching user's facebook profile information. It is only crashing on release build. I am not able to reproduce the crash even after trying it multiple times. I am fetching the profile in a separate network manager class. I have implemented it using closure and callbacks.
Below is the stack trace and crash report from Fabric.
# OS Version: 11.4.1 (15G77)
# Device: iPhone 6s
# RAM Free: 6%
# Disk Free: 14.3%
#0. Crashed: com.apple.main-thread
0 Roamer 0x104b364a4 LoginViewController.(fetchUserProfile() -> ()).(closure #1) (LoginViewController.swift:250)
1 Roamer 0x104b36d84 partial apply for LoginViewController.(fetchUserProfile() -> ()).(closure #1) (LoginViewController.swift)
2 Roamer 0x104b7ed4c specialized NetworkManager.(fetchFBProfile(((display : Int, status : String, message : String), FBProfileResponse) -> ()) -> ()).(closure #1) (NetworkManager.swift:1234)
3 Roamer 0x104b7e7a4 partial apply for NetworkManager.(fetchFBProfile(((display : Int, status : String, message : String), FBProfileResponse) -> ()) -> ()).(closure #1) (NetworkManager.swift)
4 Roamer 0x104b7e7ec HTTPURLResponse?GraphRequestResult<MyProfileRequest> (NetworkManager.swift)
5 FacebookCore 0x1058dc550 HTTPURLResponse?GraphRequestResult<A> (GraphRequestConnection.swift)
6 FacebookCore 0x1058daaac (HTTPURLResponse?, GraphRequestResult<A>)() (GraphRequestConnection.swift)
7 FacebookCore 0x1058dc8d8 static GraphRequestConnection.sdkRequestCompletion<A where ...> (from : (HTTPURLResponse?, GraphRequestResult<A>) -> ()) -> (FBSDKGraphRequestConnection?, Any?, Error?) -> () empty-list Error first-element-marker HTTPURLResponse (GraphRequestConnection.swift:152)
8 FacebookCore 0x1058dac18 static GraphRequestConnection.sdkRequestCompletion<A where ...> (from : (HTTPURLResponse?, GraphRequestResult<A>) -> ()) -> (FBSDKGraphRequestConnection?, Any?, Error?) -> () empty-list Error first-element-marker HTTPURLResponse (GraphRequestConnection.swift)
9 FacebookCore 0x1058dc5f8 FBSDKGraphRequestConnection?Any?Error? (GraphRequestConnection.swift)
10 FacebookCore 0x1058dc4bc (FBSDKGraphRequestConnection?, Any?, Error?)() (GraphRequestConnection.swift)
11 FacebookCore 0x1058c58bc FBSDKGraphRequestConnection?Any?Error? (AccessToken.swift)
12 FBSDKCoreKit 0x1056a43fc -[FBSDKGraphRequestMetadata invokeCompletionHandlerForConnection:withResults:error:] (FBSDKGraphRequestMetadata.m:48)
13 FBSDKCoreKit 0x1056a1d2c __82-[FBSDKGraphRequestConnection processResultBody:error:metadata:canNotifyDelegate:]_block_invoke (FBSDKGraphRequestConnection.m:754)
14 FBSDKCoreKit 0x1056a1b88 -[FBSDKGraphRequestConnection processResultBody:error:metadata:canNotifyDelegate:] (FBSDKGraphRequestConnection.m:818)
15 FBSDKCoreKit 0x1056a163c __64-[FBSDKGraphRequestConnection completeWithResults:networkError:]_block_invoke (FBSDKGraphRequestConnection.m:738)
16 CoreFoundation 0x1825a0a20 -[__NSArrayM enumerateObjectsWithOptions:usingBlock:] + 216
17 FBSDKCoreKit 0x1056a13e0 -[FBSDKGraphRequestConnection completeWithResults:networkError:] (FBSDKGraphRequestConnection.m:717)
18 FBSDKCoreKit 0x1056a087c -[FBSDKGraphRequestConnection completeFBSDKURLSessionWithResponse:data:networkError:] (FBSDKGraphRequestConnection.m:582)
19 FBSDKCoreKit 0x10569ea54 __36-[FBSDKGraphRequestConnection start]_block_invoke_2 (FBSDKGraphRequestConnection.m:222)
20 libdispatch.dylib 0x181fb8aa0 _dispatch_call_block_and_release + 24
21 libdispatch.dylib 0x181fb8a60 _dispatch_client_callout + 16
22 libdispatch.dylib 0x181fc565c _dispatch_main_queue_callback_4CF$VARIANT$mp + 1012
23 CoreFoundation 0x18266f070 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
24 CoreFoundation 0x18266cbc8 __CFRunLoopRun + 2272
25 CoreFoundation 0x18258cda8 CFRunLoopRunSpecific + 552
26 GraphicsServices 0x184572020 GSEventRunModal + 100
27 UIKit 0x18c5ac758 UIApplicationMain + 236
28 Roamer 0x104b1fbf8 main (DetailsCell.swift:28)
29 libdyld.dylib 0x18201dfc0 start + 4
--
Below is the function in LoginViewController from where I am calling the fetchFBProfile function in NetworkManager:
func fetchUserProfile()
{
NetworkManager.sharedInstance.fetchFBProfile() { [unowned self] (responseStatus: ResponseStatus, responseObj: FBProfileResponse) in
if responseStatus.status == "Success"
{
self.fbSignIn(responseObj)
}
else{
if responseStatus.display == 1
{
self.showBanner(Strings.failureHeaderMsg, responseStatus.message, true, true)
}
else{
self.showBanner(Strings.failureHeaderMsg, Strings.serverErrorMsg, true, true)
}
}
}
}
Below is the fetchFBProfile function in NetworkManager:
func fetchFBProfile( _ completion: #escaping GenericResponseWithObj<FBProfileResponse>) -> Void {
let connection = GraphRequestConnection()
progress.show(style: ProgressStyle())
connection.add(MyProfileRequest()) { response, result in
switch result {
case .success(let response):
let fBProfileResponse = FBProfileResponse()
fBProfileResponse.birthday = response.birthday
fBProfileResponse.email = response.email
fBProfileResponse.gender = response.gender
fBProfileResponse.id = response.id
fBProfileResponse.locale = response.locale
fBProfileResponse.name = response.name
fBProfileResponse.profilePictureUrl = response.profilePictureUrl
completion((0, "Success", "Facebook SignIn Successful"), fBProfileResponse)
case .failed(let error):
print("Custom Graph Request Failed: \(error)")
self.progress.dismiss()
completion((0, "Failure", "Couldn't fetch user response"), FBProfileResponse())
}
}
connection.start()
}
I can't understand the crash report from fabric and also the app is working flawlessly on my end. Any help would be deeply appreciated. Thanks
My iOS app does not use any networking and works fine on my iPhone, but Apple rejected it supposedly due to IPv6 incompatibility issues.
2. 1 PERFORMANCE: APP COMPLETENESS
Performance - 2.1
Your app crashes on iPhone running iOS 10.0.3 connected to an IPv6 network when we:
Specifically, we found your app crashes when we tap “Analyze.”
We have attached detailed crash logs to help troubleshoot this issue.
However when I symbolicated the crash report they sent, it shows a particular thread crashed. The backtrace is below.
Thread 5 name: Dispatch queue: com.apple.HealthKit.HKHealthStore.client.0x1700f6d00
Thread 5 Crashed:
0 libswiftCore.dylib 0x0000000100273ae8 _assertionFailed(StaticString, String, StaticString, UInt, flags : UInt32) -> Never (__hidden#14874_:167)
1 libswiftCore.dylib 0x0000000100273ae8 _assertionFailed(StaticString, String, StaticString, UInt, flags : UInt32) -> Never (__hidden#14874_:167)
2 PickerTest 0x00000001000c1d1c type metadata accessor for String? (PyschicBrain.swift:0)
3 PickerTest 0x00000001000bfe78 PsychicBrain.(isHeartRateInfoAvailableForDates() -> Bool).(closure #1) (PyschicBrain.swift:0)
4 libdispatch.dylib 0x000000018f98d200 _dispatch_call_block_and_release + 24
5 libdispatch.dylib 0x000000018f98d1c0 _dispatch_client_callout + 16
6 libdispatch.dylib 0x000000018f99b444 _dispatch_queue_serial_drain + 928
7 libdispatch.dylib 0x000000018f9909a8 _dispatch_queue_invoke + 652
8 libdispatch.dylib 0x000000018f99b940 _dispatch_queue_override_invoke + 360
9 libdispatch.dylib 0x000000018f99d38c _dispatch_root_queue_drain + 572
10 libdispatch.dylib 0x000000018f99d0ec _dispatch_worker_thread3 + 124
11 libsystem_pthread.dylib 0x000000018fb952c8 _pthread_wqthread + 1288
12 libsystem_pthread.dylib 0x000000018fb94db4 start_wqthread + 4
Stack frame #3 (above) says the closure in the function isHeartRateInfoAvailableForDates() failed, which means the HKSampleQuery failed.
My question: I'm assuming this is because no heart-rate data was found for that interval. On my phone, in this scenario, samples.count() returns 0 and hence the function returns FALSE. When Apple folks test it, obviously they get a different error. I've asked Apple for console logs but I would like to know a more elegant way of error handling.
func isHeartRateInfoAvailableForDates() -> Bool {
predicate = HKQuery.predicateForSamples(withStart: pvtStartDate, end: pvtEndDate, options: HKQueryOptions())
guard let sampleType = HKSampleType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate) else {
fatalError("HKSampleType.quantityTypeForIdentifier failed")
}
let dispatchGrp = DispatchGroup()
// Entering query block
//
dispatchGrp.enter()
let query = HKSampleQuery(sampleType: sampleType, predicate: predicate, limit: Int(HKObjectQueryNoLimit), sortDescriptors: nil) {
query, results, error in
guard let samples = results as? [HKQuantitySample] else {
fatalError("An error occured fetching the user's heart rate: \(error?.localizedDescription)");
}
self.pvtSampleCount = samples.count
// leave group once query results are available
dispatchGrp.leave()
}
pvtHealthStore.execute(query)
// Now wait for the query to complete
//
dispatchGrp.wait(timeout: DispatchTime.distantFuture)
return pvtSampleCount > 0
}
We've added Today Extension to our app recently.
Its an extension with simple tableView to load data from our server, written in Swift.
But after the extension is online to our users, we've received lots of crash data from Crashlytics and also Apple is reporting same crash issue either.
However, we can't reproduce the crash, or even find the reason of crash, because is crashing on the widgetPerformUpdateWithCompletionHandler method which is called by the system.
Below is the detail of crash log, some information are replaced.
Crashed: com.apple.main-thread
0 MyAppWidget 0x100091d8c MyAppWidgetViewController.(widgetPerformUpdateWithCompletionHandler((NCUpdateResult) -> ()) -> ()).(closure #1) (MyAppWidgetViewController.swift)
1 MyAppKit 0x100603ab4 partial apply for thunk (PostService.swift)
2 MyAppKit 0x100626080 ServiceRequestPerfomer.(performRequest(A, complete : ([B]?, NSError?) -> ()?) -> ()).(closure #1) (ServiceRequestPerformer.swift:35)
3 MyAppKit 0x1006258d4 partial apply for ServiceRequestPerfomer.(performRequest(A, complete : ([B]?, NSError?) -> ()?) -> ()).(closure #1) (ServiceRequestPerformer.swift)
4 MyAppKit 0x100626b34 ServiceRequestPerfomer.((request in _3C50B415180DDC893FFCB75CD7EE7019)(A, complete : (response : Response?, error : NSError?) -> ()?) -> ()).(closure #1) (ServiceRequestPerformer.swift:144)
5 Moya 0x1004b7468 MoyaProvider.(requestNormal(A, queue : OS_dispatch_queue?, progress : (progress : ProgressResponse) -> ()?, completion : (result : Result<Response, Error>) -> ()) -> Cancellable).(closure #1).(closure #1) (Moya.swift:229)
6 Moya 0x1004b8968 MoyaProvider.((sendAlamofireRequest in _1A5616FEE5C423A992964CB19AABD52B)(Request, target : A, queue : OS_dispatch_queue?, progress : (progress : ProgressResponse) -> ()?, completion : (result : Result<Response, Error>) -> ()) -> CancellableToken).(closure #3) (Moya.swift)
7 Moya 0x1004b57b8 partial apply for MoyaProvider.((sendAlamofireRequest in _1A5616FEE5C423A992964CB19AABD52B)(Request, target : A, queue : OS_dispatch_queue?, progress : (progress : ProgressResponse) -> ()?, completion : (result : Result<Response, Error>) -> ()) -> CancellableToken).(closure #3) (Moya.swift)
8 Alamofire 0x1002cff64 Request.(response(queue : OS_dispatch_queue?, completionHandler : (NSURLRequest?, NSHTTPURLResponse?, NSData?, NSError?) -> ()) -> Self).(closure #1).(closure #1) (ResponseSerialization.swift)
9 libdispatch.dylib 0x1819e14bc _dispatch_call_block_and_release + 24
10 libdispatch.dylib 0x1819e147c _dispatch_client_callout + 16
11 libdispatch.dylib 0x1819e6b84 _dispatch_main_queue_callback_4CF + 1844
12 CoreFoundation 0x181f4cd50 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
13 CoreFoundation 0x181f4abb8 __CFRunLoopRun + 1628
14 CoreFoundation 0x181e74c50 CFRunLoopRunSpecific + 384
15 GraphicsServices 0x18375c088 GSEventRunModal + 180
16 UIKit 0x18715e088 UIApplicationMain + 204
17 libxpc.dylib 0x181c38ce0 _xpc_objc_main + 784
18 libxpc.dylib 0x181c3a9dc xpc_main + 200
19 Foundation 0x182a57d60 service_connection_handler + 170
20 PlugInKit 0x18929ac48 -[PKService run] + 544
21 PlugInKit 0x18929a8dc +[PKService main] + 56
22 PlugInKit 0x18929ac6c +[PKService _defaultRun:arguments:] + 20
23 libextension.dylib 0x18286a058 NSExtensionMain + 64
24 libdispatch.dylib 0x181a128b8 (Missing)
And the code of widgetPerformUpdateWithCompletionHandler
func widgetPerformUpdateWithCompletionHandler(completionHandler: ((NCUpdateResult) -> Void)) {
// Perform any setup necessary in order to update the view.
// If an error is encountered, use NCUpdateResult.Failed
// If there's no update required, use NCUpdateResult.NoData
// If there's an update, use NCUpdateResult.NewData
let options: [String: AnyObject] = [DCKPostPopularAttributeName : true.stringValue,
DCKPaginationLimitAttributeName : 5]
postService.posts(options: options) { (posts, error) in
let historyPosts = self.userDefaults.arrayForKey(MyAppWidgetViewController.WidgetPostReadIdentifier) as? [UInt]
if let historyPosts = historyPosts {
self.posts = posts!.filter({ (Post) -> Bool in
return !historyPosts.contains(Post.id)
})
} else {
self.posts = posts!
}
self.tableView.reloadData()
self.tableView.hidden = false;
self.loadingLabel?.hidden = true
self.activityIndicator?.stopAnimating()
let contentSize = self.tableView.contentSize
self.preferredContentSize = CGSizeMake(CGRectGetWidth(self.view.frame), contentSize.height);
self.loadMorePostsIfNeeded()
}
completionHandler(NCUpdateResult.NewData)
}
The strange thing is:
We haven't encountered the crash issue while we're using our Today Extension normally (It should show Unable to load if today extension crashes)
We didn't receive any issue from our users reporting that today extension isn't working.
We've found the same crash log on our device, but the today extension is working normally as 1. described. And also, the time of crash log recorded, I'm not using my phone!
So we're guessing it's a 「fake」crash, the crash is logged, but the extension didn't really crashed.
Does anybody facing the same issue?
Thank you!
Answering my own question,
#matt is right, Now I am calling the completionHandler only when data fetch task completes, instead of always call the completionHandler at the last of widgetPerformUpdateWithCompletionHandler method.
I didn't receive crashes anymore, the problem was solved!
I have following snippets of code where I have crash on some devices:
Crashed: com.apple.root.default-qos
EXC_BAD_ACCESS KERN_INVALID_ADDRESS at 0x00000000cbd
Code:
var obj:AnyObject = command.arguments[0] as AnyObject!
var theData:AnyObject = obj["getContactImagesByEmails"] as AnyObject!
if let contactImagesByEmails:AnyObject = obj["emails"]{
if contactImagesByEmails is Array<String>{
/*line 176*/ let array:Array<String> =
contactImagesByEmails as Array<String> // CRASH happens here
results = WmSqliteImagesModel.getInstance.getImagesByEmailAsWmContactImage(array) as Dictionary<String,AnyObject>
}
}
Full stack trace
Thread : Crashed: com.apple.root.default-qos
0 libswiftCore.dylib 0x0000000100559794 swift_unknownRetain + 32
1 MyApp 0x000000010017c8a0 MyApp.Plugin.(getContactImagesByEmails (MyApp.Plugin) -> (ObjectiveC.CDVInvokedUrlCommand) -> ()).(closure #1) (Plugin.swift:176)
2 MyApp 0x000000010017c8a0 MyApp.Plugin.(getContactImagesByEmails (MyApp.Plugin) -> (ObjectiveC.CDVInvokedUrlCommand) -> ()).(closure #1) (Plugin.swift:176)
3 MyApp 0x00000001001790b0 partial apply forwarder for reabstraction thunk helper from #callee_owned () -> (#unowned ()) to #callee_owned (#in ()) -> (#out ()) with unmangled suffix "125" (Plugin.swift:62)
4 MyApp 0x0000000100179120 partial apply forwarder for reabstraction thunk helper from #callee_owned (#in ()) -> (#out ()) to #callee_owned () -> (#unowned ()) with unmangled suffix "128" (Plugin.swift:62)
5 libdispatch.dylib 0x00000001937e13ac _dispatch_call_block_and_release + 24
6 libdispatch.dylib 0x00000001937e136c _dispatch_client_callout + 16
7 libdispatch.dylib 0x00000001937ed40c _dispatch_root_queue_drain + 1152
8 libdispatch.dylib 0x00000001937ee75c _dispatch_worker_thread3 + 108
9 libsystem_pthread.dylib 0x00000001939bd2e4 _pthread_wqthread + 816
The Plugin.swift:176 points to:
let array:Array<String> = contactImagesByEmails as Array<String>
Do I miss something? I think this code should be safe.
if contactImagesByEmails is Array<String> returns true, why contactImagesByEmails as Array<String> fails?
Please help,
[EDIT]
command has type of CDVInvokedUrlCommand
#interface CDVInvokedUrlCommand : NSObject {
NSString* _callbackId;
NSString* _className;
NSString* _methodName;
NSArray* _arguments;
}
I don't know if this can actually fixes the problem, but there's a bit of redundancy in the 2 ifs and the following let. It can simply be written as:
if let contactImagesByEmails = obj["emails"] as? Array<String> {
results = WmSqliteImagesModel.getInstance.getImagesByEmailAsWmContactImage(contactImagesByEmails) as Dictionary<String,AnyObject>
}
Moreover, it would be safer to combine optional binding and optional downcast when invoking getImagesByEmailAsWmContactImage
if let results = WmSqliteImagesModel.getInstance.getImagesByEmailAsWmContactImage(contactImagesByEmails) as? Dictionary<String,AnyObject> {
...
}
Last, are you sure getInstance is a property and not a method? Shouldn't it be:
if let results = WmSqliteImagesModel.getInstance().getImagesByEmailAsWmContactImage(contactImagesByEmails) as? Dictionary<String,AnyObject> {
...
}
Perhaps try an alternate approach to getting the casted value:
if let contactImagesByEmails = obj["emails"] as? [String] {
results = WmSqliteImagesModel.getInstance.getImagesByEmailAsWmContactImage(contactImagesByEmails) as Dictionary<String,AnyObject>
}
I also wonder if your crash is not from naming your variable "array" in your original code...
Simplify this step by step with fewer references to AnyObject (and certainly not AnyObject!). The compiler is probably letting through something that is illegal, because when you start pulling out AnyObject you're saying "I know exactly what I'm doing; don't check this."
You'd expect this code to be something like:
let obj = command.arguments[0]
if let contactImagesByEmails = obj["emails"] as? [String] {
results = WmSqliteImagesModel.getInstance.getImagesByEmailAsWmContactImage(array) as? [String: AnyObject]
}
In the end results would be a [String:AnyObject]?
The key point here is that you should get rid of as many references to AnyObject as you can, and you should use if-let-as? to determine if the types are what you expect.
The fact that command.arguments is filled with things of various types that you have to type-check is pretty dangerous and a sign of a serious design problem. If there really are several types in there, you should use an enum rather than type-checking against random things like [String:AnyObject]. That's what enums are explicitly for. (If this is bridging from ObjC; enums may not be possible here, but even in ObjC, the right answer is seldom to have an NSArray filled with heterogeneous types. You create a class there to hold them rather than an enum.)