{"action":"created","issue":{"url":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/3112","repository_url":"https://api.github.com/repos/facebook/AsyncDisplayKit","labels_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/3112/labels{/name}","comments_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/3112/comments","events_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/3112/events","html_url":"https://github.com/facebook/AsyncDisplayKit/issues/3112","id":211093215,"number":3112,"title":"Unavoidable crash when implementing ASImageCacheProtocol in Swift due to incorrect bridging","user":{"login":"flovouin","id":5155149,"avatar_url":"https://avatars0.githubusercontent.com/u/5155149?v=3","gravatar_id":"","url":"https://api.github.com/users/flovouin","html_url":"https://github.com/flovouin","followers_url":"https://api.github.com/users/flovouin/followers","following_url":"https://api.github.com/users/flovouin/following{/other_user}","gists_url":"https://api.github.com/users/flovouin/gists{/gist_id}","starred_url":"https://api.github.com/users/flovouin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/flovouin/subscriptions","organizations_url":"https://api.github.com/users/flovouin/orgs","repos_url":"https://api.github.com/users/flovouin/repos","events_url":"https://api.github.com/users/flovouin/events{/privacy}","received_events_url":"https://api.github.com/users/flovouin/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":3,"created_at":"2017-03-01T14:14:57Z","updated_at":"2017-03-18T08:04:19Z","closed_at":"2017-03-18T08:04:19Z","body":"Hi guys,\r\n\r\nI had asked questions about the cache / download mechanism of the `ASNetworkImageNode` a while back and successfully implemented the custom logic I needed.\r\nI currently have an `ImageManager` class (in Swift) in my app that implements both `ASImageCacheProtocol` and `ASImageDownloaderProtocol`.\r\nEverything works great except when `ASNetworkImageNode.URL` is null. In this case, a `nil` URL is forwarded to my implementation of `clearFetchedImageFromCacheWithURL`. The problem is that, in Swift, this method doesn't take an optional but only a defined `URL`. This makes bridging crash with the following stack trace:\r\n\r\n```\r\n* thread #1: tid = 0x29f98d, 0x0000000101ec0af4 libswiftFoundation.dylib`static Foundation.DateComponents._unconditionallyBridgeFromObjectiveC (Swift.Optional<__ObjC.NSDateComponents>) -> Foundation.DateComponents with unmangled suffix \"_merged\" + 96, queue = 'com.apple.main-thread', stop reason = EXC_BREAKPOINT (code=1, subcode=0x101ec0af4)\r\n  * frame #0: 0x0000000101ec0af4 libswiftFoundation.dylib`static Foundation.DateComponents._unconditionallyBridgeFromObjectiveC (Swift.Optional<__ObjC.NSDateComponents>) -> Foundation.DateComponents with unmangled suffix \"_merged\" + 96\r\n    frame #1: 0x0000000100336f68 MyApp`@objc ImageManager.clearFetchedImageFromCache(with : URL) -> () + 64 at ImageManager.swift:0\r\n    frame #2: 0x0000000101089b5c AsyncDisplayKit`::-[ASNetworkImageNode _cancelDownloadAndClearImage](self=0x0000000102977000, _cmd=\"_cancelDownloadAndClearImage\") + 152 at ASNetworkImageNode.mm:438\r\n    frame #3: 0x0000000101089058 AsyncDisplayKit`::-[ASNetworkImageNode didExitPreloadState](self=0x0000000102977000, _cmd=\"didExitPreloadState\") + 160 at ASNetworkImageNode.mm:347\r\n    frame #4: 0x0000000101015f84 AsyncDisplayKit`::-[ASDisplayNode setInterfaceState:](self=0x0000000102977000, _cmd=\"setInterfaceState:\", newState=1) + 1080 at ASDisplayNode.mm:3361\r\n    frame #5: 0x0000000101015a84 AsyncDisplayKit`::__46-[ASDisplayNode recursivelySetInterfaceState:]_block_invoke((null)=<unavailable>, node=0x0000000102977000) + 68 at ASDisplayNode.mm:3309\r\n    frame #6: 0x00000001010220b8 AsyncDisplayKit`::ASDisplayNodePerformBlockOnEveryNode(layer=0x000000017014de10, node=0x0000000102977000, traverseSublayers=YES, block=0x0000000101015a40)(ASDisplayNode *)) + 1232 at ASDisplayNodeExtras.mm:87\r\n    frame #7: 0x00000001010222a0 AsyncDisplayKit`::ASDisplayNodePerformBlockOnEveryNode(layer=0x000000017414a240, node=0x00000001029cda00, traverseSublayers=YES, block=0x0000000101015a40)(ASDisplayNode *)) + 1720 at ASDisplayNodeExtras.mm:97\r\n    frame #8: 0x0000000101015a08 AsyncDisplayKit`::-[ASDisplayNode recursivelySetInterfaceState:](self=0x00000001029cda00, _cmd=\"recursivelySetInterfaceState:\", newInterfaceState=1) + 188 at ASDisplayNode.mm:3308\r\n    frame #9: 0x00000001010987e8 AsyncDisplayKit`::-[ASRangeController _updateVisibleNodeIndexPaths](self=0x00000001700b89c0, _cmd=\"_updateVisibleNodeIndexPaths\") + 4144 at ASRangeController.mm:373\r\n    frame #10: 0x0000000101097210 AsyncDisplayKit`::-[ASRangeController updateIfNeeded](self=0x00000001700b89c0, _cmd=\"updateIfNeeded\") + 96 at ASRangeController.mm:148\r\n    frame #11: 0x0000000100fb89a4 AsyncDisplayKit`::-[ASCollectionView layoutSubviews](self=0x0000000102846a00, _cmd=\"layoutSubviews\") + 524 at ASCollectionView.mm:1352\r\n    frame #12: 0x0000000195e6ba80 UIKit`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1196\r\n    frame #13: 0x00000001933199d8 QuartzCore`-[CALayer layoutSublayers] + 148\r\n    frame #14: 0x0000000100f6b5a4 AsyncDisplayKit`::-[_ASDisplayLayer layoutSublayers](self=0x0000000170148da0, _cmd=\"layoutSublayers\") + 368 at _ASDisplayLayer.mm:130\r\n    frame #15: 0x000000019330e4cc QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 292\r\n    frame #16: 0x000000019330e38c QuartzCore`CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 32\r\n    frame #17: 0x000000019328b3e0 QuartzCore`CA::Context::commit_transaction(CA::Transaction*) + 252\r\n    frame #18: 0x00000001932b2a68 QuartzCore`CA::Transaction::commit() + 512\r\n    frame #19: 0x000000019320ee7c QuartzCore`CA::Display::DisplayLink::dispatch_items(unsigned long long, unsigned long long, unsigned long long) + 616\r\n    frame #20: 0x0000000190226094 IOKit`IODispatchCalloutFromCFMessage + 372\r\n    frame #21: 0x000000018ff4ee50 CoreFoundation`__CFMachPortPerform + 180\r\n    frame #22: 0x000000018ff67218 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 56\r\n    frame #23: 0x000000018ff669cc CoreFoundation`__CFRunLoopDoSource1 + 436\r\n    frame #24: 0x000000018ff644b0 CoreFoundation`__CFRunLoopRun + 1840\r\n    frame #25: 0x000000018fe922b8 CoreFoundation`CFRunLoopRunSpecific + 444\r\n    frame #26: 0x0000000191946198 GraphicsServices`GSEventRunModal + 180\r\n    frame #27: 0x0000000195ed97fc UIKit`-[UIApplication _run] + 684\r\n    frame #28: 0x0000000195ed4534 UIKit`UIApplicationMain + 208\r\n    frame #29: 0x000000010021cd2c MyApp`main + 140 at AppDelegate.swift:12\r\n    frame #30: 0x000000018ee755b8 libdyld.dylib`start + 4\r\n```\r\n\r\nThe problem is that I cannot prevent this exception. The work around I have found is to ensure `ASNetworkImageNode.URL` is never `nil`, but this forces me to declare fake URLs pointing to nothing.\r\nI guess the problem can either be solved by modifying the `NS_ASSUME_NONNULL` around `ASImageProtocol.h`, or more simply by not calling `clearFetchedImageFromCacheWithURL` in `_cancelDownloadAndClearImage` when `_URL` is `nil`.\r\nI'm currently using ASDK 2.0.2, but the problem still occurs on `master`.\r\n\r\nWhat do you guys think?\r\n\r\nThanks,\r\nFlo"},"comment":{"url":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/comments/287524029","html_url":"https://github.com/facebook/AsyncDisplayKit/issues/3112#issuecomment-287524029","issue_url":"https://api.github.com/repos/facebook/AsyncDisplayKit/issues/3112","id":287524029,"user":{"login":"flovouin","id":5155149,"avatar_url":"https://avatars0.githubusercontent.com/u/5155149?v=3","gravatar_id":"","url":"https://api.github.com/users/flovouin","html_url":"https://github.com/flovouin","followers_url":"https://api.github.com/users/flovouin/followers","following_url":"https://api.github.com/users/flovouin/following{/other_user}","gists_url":"https://api.github.com/users/flovouin/gists{/gist_id}","starred_url":"https://api.github.com/users/flovouin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/flovouin/subscriptions","organizations_url":"https://api.github.com/users/flovouin/orgs","repos_url":"https://api.github.com/users/flovouin/repos","events_url":"https://api.github.com/users/flovouin/events{/privacy}","received_events_url":"https://api.github.com/users/flovouin/received_events","type":"User","site_admin":false},"created_at":"2017-03-18T08:04:19Z","updated_at":"2017-03-18T08:04:19Z","body":"Solved by #3190 \\o/"}}
{"actor":{"display_login":"flovouin"}}