Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ASImageNode] Clarify documentation on why resizable images should be Stretched and not Tiled #439

Closed
Kaspik opened this issue Jul 14, 2017 · 6 comments
Assignees

Comments

@Kaspik
Copy link
Contributor

Kaspik commented Jul 14, 2017

Version: Texture (2.3.3)
Repro: 100%
Problem:
If ASImageNode gets stretchable image:

_backgroundImageNode.image = [UIImage imageNamed:@"card_stretchable"];

but stretching is defined in Images.assets via Slicing - then app crashes.
It's not happening if code looks like:

_backgroundImageNode.image = [[UIImage imageNamed:@"card_stretchable"] resizableImageWithCapInsets:UIEdgeInsetsMake(12.0f, 13.0f, 12.0f, 13.0f) resizingMode:UIImageResizingModeStretch];

Full setup of ASImageNode:

_backgroundImageNode = [[ASImageNode alloc] init];
_backgroundImageNode.image = [UIImage imageNamed:@"card_stretchable"];
_backgroundImageNode.layerBacked = YES;

Example app: ASDK button

Crash info:

*** Assertion failure in void ASDisplayNodeSetupLayerContentsWithResizableImage(CALayer *__strong, UIImage *__strong)(),path_to_project/Pods/Texture/Source/Private/_ASCoreAnimationExtras.mm:37
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'the resizing mode of image should be stretch; if not, then its insets must be all-zero'
*** First throw call stack:
(
	0   CoreFoundation                      0x000000010c579b0b __exceptionPreprocess + 171
	1   libobjc.A.dylib                     0x000000010dc09141 objc_exception_throw + 48
	2   CoreFoundation                      0x000000010c57dcf2 +[NSException raise:format:arguments:] + 98
	3   Foundation                          0x000000010d7d869b -[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:] + 165
	4   AsyncDisplayKit                     0x0000000108243a21 ASDisplayNodeSetupLayerContentsWithResizableImage + 1121
	5   AsyncDisplayKit                     0x00000001082d168d __64-[ASDisplayNode(AsyncDisplay) displayAsyncLayer:asynchronously:]_block_invoke_2 + 1005
	6   AsyncDisplayKit                     0x0000000108233886 -[ASAsyncTransactionOperation callAndReleaseCompletionBlock:] + 134
	7   AsyncDisplayKit                     0x000000010823a502 -[_ASAsyncTransaction completeTransaction] + 482
	8   AsyncDisplayKit                     0x000000010823a2a0 __29-[_ASAsyncTransaction commit]_block_invoke + 384
	9   libdispatch.dylib                   0x000000010ee174a6 _dispatch_call_block_and_release + 12
	10  libdispatch.dylib                   0x000000010ee4005c _dispatch_client_callout + 8
	11  libdispatch.dylib                   0x000000010ee2140b _dispatch_main_queue_callback_4CF + 411
	12  CoreFoundation                      0x000000010c53e909 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
	13  CoreFoundation                      0x000000010c504ae4 __CFRunLoopRun + 2164
	14  CoreFoundation                      0x000000010c504016 CFRunLoopRunSpecific + 406
	15  GraphicsServices                    0x0000000111477a24 GSEventRunModal + 62
	16  UIKit                               0x0000000109609134 UIApplicationMain + 159
	17  ClassDojo                           0x0000000107073fb4 main + 132
	18  libdyld.dylib                       0x000000010ee8c65d start + 1

bt all info:

* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
    frame #0: 0x000000010f89fd42 libsystem_kernel.dylib`__pthread_kill + 10
    frame #1: 0x000000010f8d7457 libsystem_pthread.dylib`pthread_kill + 90
    frame #2: 0x000000010ef3488f libsystem_c.dylib`abort + 127
    frame #3: 0x000000010ed09ce5 libc++abi.dylib`abort_message + 245
    frame #4: 0x000000010ed24cbd libc++abi.dylib`default_terminate_handler() + 265
    frame #5: 0x000000010dc093c4 libobjc.A.dylib`_objc_terminate() + 103
    frame #6: 0x000000010ed21f29 libc++abi.dylib`std::__terminate(void (*)()) + 8
    frame #7: 0x000000010ed21fa3 libc++abi.dylib`std::terminate() + 51
    frame #8: 0x000000010dc09343 libobjc.A.dylib`objc_terminate + 9
    frame #9: 0x000000010ee40070 libdispatch.dylib`_dispatch_client_callout + 28
    frame #10: 0x000000010ee2140b libdispatch.dylib`_dispatch_main_queue_callback_4CF + 411
    frame #11: 0x000000010c53e909 CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
    frame #12: 0x000000010c504ae4 CoreFoundation`__CFRunLoopRun + 2164
    frame #13: 0x000000010c504016 CoreFoundation`CFRunLoopRunSpecific + 406
    frame #14: 0x0000000111477a24 GraphicsServices`GSEventRunModal + 62
    frame #15: 0x0000000109609134 UIKit`UIApplicationMain + 159
  * frame #16: 0x0000000107073fb4 ClassDojo`main(argc=1, argv=0x00007fff59131598) at main.m:16
    frame #17: 0x000000010ee8c65d libdyld.dylib`start + 1
    frame #18: 0x000000010ee8c65d libdyld.dylib`start + 1

  thread #2, queue = 'com.apple.libdispatch-manager'
    frame #0: 0x000000010f8a0dc6 libsystem_kernel.dylib`kevent_qos + 10
    frame #1: 0x000000010ee31efb libdispatch.dylib`_dispatch_mgr_wait_for_event + 66
    frame #2: 0x000000010ee2b872 libdispatch.dylib`_dispatch_mgr_invoke + 197
    frame #3: 0x000000010ee2b6a7 libdispatch.dylib`_dispatch_mgr_thread + 54

  thread #5
    frame #0: 0x000000010f8a044e libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010f8d4621 libsystem_pthread.dylib`_pthread_wqthread + 1426
    frame #2: 0x000000010f8d407d libsystem_pthread.dylib`start_wqthread + 13

  thread #6, name = 'com.apple.uikit.eventfetch-thread'
    frame #0: 0x000000010f89834a libsystem_kernel.dylib`mach_msg_trap + 10
    frame #1: 0x000000010f897797 libsystem_kernel.dylib`mach_msg + 55
    frame #2: 0x000000010c5052e4 CoreFoundation`__CFRunLoopServiceMachPort + 212
    frame #3: 0x000000010c5047a9 CoreFoundation`__CFRunLoopRun + 1337
    frame #4: 0x000000010c504016 CoreFoundation`CFRunLoopRunSpecific + 406
    frame #5: 0x000000010d6f2600 Foundation`-[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 274
    frame #6: 0x000000010d777c69 Foundation`-[NSRunLoop(NSRunLoop) runUntilDate:] + 87
    frame #7: 0x000000010a07a8a1 UIKit`-[UIEventFetcher threadMain] + 118
    frame #8: 0x000000010d702131 Foundation`__NSThread__start__ + 1197
    frame #9: 0x000000010f8d493b libsystem_pthread.dylib`_pthread_body + 180
    frame #10: 0x000000010f8d4887 libsystem_pthread.dylib`_pthread_start + 286
    frame #11: 0x000000010f8d408d libsystem_pthread.dylib`thread_start + 13

  thread #9
    frame #0: 0x000000010f8a044e libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010f8d4621 libsystem_pthread.dylib`_pthread_wqthread + 1426
    frame #2: 0x000000010f8d407d libsystem_pthread.dylib`start_wqthread + 13

  thread #10, name = 'com.apple.NSURLConnectionLoader'
    frame #0: 0x000000010f89834a libsystem_kernel.dylib`mach_msg_trap + 10
    frame #1: 0x000000010f897797 libsystem_kernel.dylib`mach_msg + 55
    frame #2: 0x000000010c5052e4 CoreFoundation`__CFRunLoopServiceMachPort + 212
    frame #3: 0x000000010c5047a9 CoreFoundation`__CFRunLoopRun + 1337
    frame #4: 0x000000010c504016 CoreFoundation`CFRunLoopRunSpecific + 406
    frame #5: 0x000000010b8e2dff CFNetwork`+[NSURLConnection(Loader) _resourceLoadLoop:] + 406
    frame #6: 0x000000010d702131 Foundation`__NSThread__start__ + 1197
    frame #7: 0x000000010f8d493b libsystem_pthread.dylib`_pthread_body + 180
    frame #8: 0x000000010f8d4887 libsystem_pthread.dylib`_pthread_start + 286
    frame #9: 0x000000010f8d408d libsystem_pthread.dylib`thread_start + 13

  thread #12
    frame #0: 0x000000010f8a044e libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010f8d4621 libsystem_pthread.dylib`_pthread_wqthread + 1426
    frame #2: 0x000000010f8d407d libsystem_pthread.dylib`start_wqthread + 13

  thread #13
    frame #0: 0x000000010f89fbf2 libsystem_kernel.dylib`__psynch_cvwait + 10
    frame #1: 0x000000010f8d57fa libsystem_pthread.dylib`_pthread_cond_wait + 712
    frame #2: 0x0000000107e5ddbd libc++.1.dylib`std::__1::condition_variable::wait(std::__1::unique_lock<std::__1::mutex>&) + 47
    frame #3: 0x0000000116e13c6c JavaScriptCore`void std::__1::condition_variable_any::wait<std::__1::unique_lock<bmalloc::Mutex> >(std::__1::unique_lock<bmalloc::Mutex>&) + 108
    frame #4: 0x0000000116e13beb JavaScriptCore`bmalloc::AsyncTask<bmalloc::Heap, void (bmalloc::Heap::*)()>::threadRunLoop() + 155
    frame #5: 0x0000000116e13abd JavaScriptCore`bmalloc::AsyncTask<bmalloc::Heap, void (bmalloc::Heap::*)()>::threadEntryPoint(bmalloc::AsyncTask<bmalloc::Heap, void (bmalloc::Heap::*)()>*) + 29
    frame #6: 0x0000000116e13d6d JavaScriptCore`void* std::__1::__thread_proxy<std::__1::tuple<void (*)(bmalloc::AsyncTask<bmalloc::Heap, void (bmalloc::Heap::*)()>*), bmalloc::AsyncTask<bmalloc::Heap, void (bmalloc::Heap::*)()>*> >(void*) + 93
    frame #7: 0x000000010f8d493b libsystem_pthread.dylib`_pthread_body + 180
    frame #8: 0x000000010f8d4887 libsystem_pthread.dylib`_pthread_start + 286
    frame #9: 0x000000010f8d408d libsystem_pthread.dylib`thread_start + 13

  thread #14
    frame #0: 0x000000010f8a044e libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010f8d4621 libsystem_pthread.dylib`_pthread_wqthread + 1426
    frame #2: 0x000000010f8d407d libsystem_pthread.dylib`start_wqthread + 13

  thread #15, name = 'com.apple.CFSocket.private'
    frame #0: 0x000000010f89feb6 libsystem_kernel.dylib`__select + 10
    frame #1: 0x000000010c53b6d9 CoreFoundation`__CFSocketManager + 665
    frame #2: 0x000000010f8d493b libsystem_pthread.dylib`_pthread_body + 180
    frame #3: 0x000000010f8d4887 libsystem_pthread.dylib`_pthread_start + 286
    frame #4: 0x000000010f8d408d libsystem_pthread.dylib`thread_start + 13

  thread #16
    frame #0: 0x000000010f8a044e libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010f8d4621 libsystem_pthread.dylib`_pthread_wqthread + 1426
    frame #2: 0x000000010f8d407d libsystem_pthread.dylib`start_wqthread + 13

  thread #17
    frame #0: 0x000000010f8a044e libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010f8d4621 libsystem_pthread.dylib`_pthread_wqthread + 1426
    frame #2: 0x000000010f8d407d libsystem_pthread.dylib`start_wqthread + 13

  thread #18
    frame #0: 0x000000010f8a044e libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010f8d4621 libsystem_pthread.dylib`_pthread_wqthread + 1426
    frame #2: 0x000000010f8d407d libsystem_pthread.dylib`start_wqthread + 13

  thread #19
    frame #0: 0x000000010f8a044e libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010f8d4621 libsystem_pthread.dylib`_pthread_wqthread + 1426
    frame #2: 0x000000010f8d407d libsystem_pthread.dylib`start_wqthread + 13

  thread #20
    frame #0: 0x000000010f8a044e libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010f8d4621 libsystem_pthread.dylib`_pthread_wqthread + 1426
    frame #2: 0x000000010f8d407d libsystem_pthread.dylib`start_wqthread + 13

  thread #21
    frame #0: 0x000000010f8a044e libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010f8d4621 libsystem_pthread.dylib`_pthread_wqthread + 1426
    frame #2: 0x000000010f8d407d libsystem_pthread.dylib`start_wqthread + 13

  thread #22
    frame #0: 0x000000010f8a044e libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010f8d4621 libsystem_pthread.dylib`_pthread_wqthread + 1426
    frame #2: 0x000000010f8d407d libsystem_pthread.dylib`start_wqthread + 13

  thread #23
    frame #0: 0x000000010f8a044e libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010f8d4621 libsystem_pthread.dylib`_pthread_wqthread + 1426
    frame #2: 0x000000010f8d407d libsystem_pthread.dylib`start_wqthread + 13

  thread #24
    frame #0: 0x000000010f8a044e libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010f8d4621 libsystem_pthread.dylib`_pthread_wqthread + 1426
    frame #2: 0x000000010f8d407d libsystem_pthread.dylib`start_wqthread + 13

  thread #25
    frame #0: 0x000000010f8a044e libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010f8d4621 libsystem_pthread.dylib`_pthread_wqthread + 1426
    frame #2: 0x000000010f8d407d libsystem_pthread.dylib`start_wqthread + 13

  thread #26
    frame #0: 0x000000010f8a044e libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010f8d4621 libsystem_pthread.dylib`_pthread_wqthread + 1426
    frame #2: 0x000000010f8d407d libsystem_pthread.dylib`start_wqthread + 13

  thread #27
    frame #0: 0x000000010f8a044e libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010f8d4621 libsystem_pthread.dylib`_pthread_wqthread + 1426
    frame #2: 0x000000010f8d407d libsystem_pthread.dylib`start_wqthread + 13

  thread #28
    frame #0: 0x000000010f8a044e libsystem_kernel.dylib`__workq_kernreturn + 10
    frame #1: 0x000000010f8d4621 libsystem_pthread.dylib`_pthread_wqthread + 1426
    frame #2: 0x000000010f8d407d libsystem_pthread.dylib`start_wqthread + 13
@Kaspik
Copy link
Contributor Author

Kaspik commented Jul 18, 2017

Note: Changing asset image slicing from Tiles (default) to Stretches fixes the issue. But I don't see reason why it should be stretches - because if we remove condition ASDisplayNodeCAssert(image.resizingMode == UIImageResizingModeStretch || UIEdgeInsetsEqualToEdgeInsets(image.capInsets, UIEdgeInsetsZero), @"the resizing mode of image should be stretch; if not, then its insets must be all-zero"); in _ASCoreAnimationExtras.mm - then everything works correctly as well with Tiles mode.
Probably outdated code? Or is there any reason for ModeStretch?

@ay8s
Copy link
Collaborator

ay8s commented Jul 18, 2017

Looks like its due to the FIXME at the top of ASCoreAnimationExtras. "This method does not currently handle UIImageResizingModeTile, which is the default on iOS 6.".

Not sure if the new ASDisplayNodeSetResizableContents: @appleguy added in #429 helps at all. Note the FIXME still exists there.

@Kaspik
Copy link
Contributor Author

Kaspik commented Jul 18, 2017

@ay8s I am just not sure what does it mean "not currently handle" if commenting out the assert and trying to use it works as it should.

@appleguy Did your PR changed how it works, fixed some issues, or can we revisit if it's still necessary for correct behavior?

@appleguy
Copy link
Member

@Kaspik Using Stretches in your image specification is the correct fix. Even though it may look correct when you use Tiles and comment out the assertion, what is actually happening is stretching, because this is how the GPU-accelerated CALayer features operate (the stuff done by the SetResizableContents method).

Ideally we'd have this better documented, but the assertion is there to help point this out. I'll leave this task open until I have a chance to improve the assertion message so it is more clear in explaining the reason why Texture requires using Stretch. To reiterate, it's because Stretch is significantly more efficient to use than Tile, and Tile can't be correctly implemented with this hardware-accelerated approach; we could certainly implement Tile, but it would use a lot more memory and CPU, whereas users can simply draw the image into a UIGraphicsContext manually to achieve this effect if it's needed.

Thanks for filing this - it's a very reasonable question, and a good reminder to improve the assertion.

@appleguy appleguy self-assigned this Jul 18, 2017
@appleguy appleguy changed the title [ASImageNode] Crash: App crashes with resizable image [ASImageNode] Clarify documentation on why resizable images should be Stretched and not Tiled Jul 18, 2017
@Kaspik
Copy link
Contributor Author

Kaspik commented Jul 18, 2017

@appleguy Cool, thanks for the answer!

@Kaspik
Copy link
Contributor Author

Kaspik commented Oct 24, 2018

Fixed year ago.

@Kaspik Kaspik closed this as completed Oct 24, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants