CK::Component::MountResult CKPerformMount()

in RenderCore/CKMountableHelpers.mm [40:108]


CK::Component::MountResult CKPerformMount(std::unique_ptr<CKMountInfo> &mountInfo,
                                          const RCLayout &layout,
                                          const CKViewConfiguration &viewConfiguration,
                                          const CK::Component::MountContext &context,
                                          const id<CKMountable> supercomponent,
                                          const CKMountCallbackFunction didAcquireViewFunction,
                                          const CKMountCallbackFunction willRelinquishViewFunction,
                                          const CKMountAnimationBlockCallbackFunction blockAnimationIfNeededFunction,
                                          const CKMountAnimationUnblockCallbackFunction unblockAnimationFunction)
{
  RCCAssertMainThread();

  if (!mountInfo) {
    mountInfo.reset(new CKMountInfo());
  }
  mountInfo->supercomponent = supercomponent;

  UIView *v = context.viewManager->viewForConfiguration(layout.component.class, viewConfiguration);
  if (v) {
    auto const currentMountedComponent = (id<CKMountable>)CKMountedObjectForView(v);
    BOOL didBlockAnimation = NO;
    if (blockAnimationIfNeededFunction) {
      didBlockAnimation = blockAnimationIfNeededFunction(currentMountedComponent, layout.component, context, viewConfiguration);
    }

    // Mount a view for the component if needed.
    UIView *acquiredView = nil;
    if (mountInfo->view != v) {
      relinquishMountedView(mountInfo, layout.component, willRelinquishViewFunction); // First release our old view
      [currentMountedComponent unmount]; // Then unmount old component (if any) from the new view
      CKSetMountedObjectForView(v, layout.component);
      CK::Component::AttributeApplicator::apply(v, viewConfiguration);
      acquiredView = v;
      mountInfo->view = v;
    } else {
      RCCAssert(currentMountedComponent == layout.component, @"");
    }

    @try {
      CKSetViewPositionAndBounds(v, context, layout.size);
    } @catch (NSException *exception) {
      NSString *const componentBacktraceDescription =
        RCComponentBacktraceDescription(RCComponentGenerateBacktrace(supercomponent));
      NSString *const componentChildrenDescription = RCComponentChildrenDescription(layout.children);
      RCCFatalWithCategory(exception.name, @"%@ raised %@ during mount: %@\n backtrace:%@ children:%@", layout.component.class, exception.name, exception.reason, componentBacktraceDescription, componentChildrenDescription);
    }

    mountInfo->viewContext = {v, {{0,0}, v.bounds.size}};

    // If the mount process acquired a new view, trigger the didAcquireView callback.
    if (acquiredView && didAcquireViewFunction) {
      didAcquireViewFunction(layout.component, acquiredView);
    }

    if (didBlockAnimation && unblockAnimationFunction) {
      unblockAnimationFunction();
    }

    return {.mountChildren = YES, .contextForChildren = context.childContextForSubview(v, didBlockAnimation)};
  } else {
    RCCAssertWithCategory(mountInfo->view == nil, layout.component.class,
                          @"%@ should not have a mounted %@ after previously being mounted without a view.\n%@",
                          layout.component.class,
                          [mountInfo->view class],
                          RCComponentBacktraceDescription(RCComponentGenerateBacktrace(layout.component)));
    mountInfo->viewContext = {context.viewManager->view, {context.position, layout.size}};
    return {.mountChildren = YES, .contextForChildren = context};
  }
}