managarten/maerchenzauber/apps/mobile/docs/IOS_CRASH_PREVENTION.md
Till-JS e7f5f942f3 chore: initial commit - consolidate 4 projects into monorepo
Projects included:
- maerchenzauber (NestJS backend + Expo mobile + SvelteKit web + Astro landing)
- manacore (Expo mobile + SvelteKit web + Astro landing)
- manadeck (NestJS backend + Expo mobile + SvelteKit web)
- memoro (Expo mobile + SvelteKit web + Astro landing)

This commit preserves the current state before monorepo restructuring.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 23:38:24 +01:00

6 KiB

iOS Crash Prevention - Quick Reference

Last Updated: 2025-11-02

This is a quick reference for common iOS crash patterns and how to prevent them. For the complete debugging journey, see DEEPLINK_CRASH_FIX.md.


1. LinearGradient Crashes

DON'T DO THIS:

import { LinearGradient } from 'expo-linear-gradient';

const styles = StyleSheet.create({
  gradient: {
    width: '100%',  // Can be undefined during navigation!
    height: 100,
  }
});

<LinearGradient
  colors={['#000', '#fff']}
  style={styles.gradient}
/>

Why it crashes: During navigation (especially deeplinks), width: '100%' can be undefined before parent layout resolves. CoreGraphics crashes trying to render with invalid dimensions.

DO THIS INSTEAD:

const styles = StyleSheet.create({
  gradient: {
    alignSelf: 'stretch',  // More reliable than width: '100%'
    minWidth: 200,  // Ensure valid dimensions for CoreGraphics
    height: 100,
  }
});

<LinearGradient
  colors={['#000', '#fff']}
  style={styles.gradient}
/>

Crash signature: CoreGraphics CGContextDrawLinearGradient + 236


2. Image Loading During Navigation

DON'T DO THIS:

import { Image } from 'expo-image';

<Image
  source={{ uri: imageUrl }}
  transition={300}  // Conflicts with navigation animations!
/>

Why it crashes: Image transitions can conflict with navigation transitions, causing CoreGraphics to deallocate images while still rendering.

DO THIS INSTEAD:

<Image
  source={{ uri: imageUrl }}
  transition={0}  // Disable for navigation screens
  recyclingKey={uniqueId}  // Help expo-image reuse instances
  cachePolicy="memory-disk"  // Proper caching
/>

Crash signature: CoreGraphics image_finalize, CA::Layer::~Layer()


3. Navigation Snapshots

DON'T DO THIS:

// Missing _layout.tsx in directory
app/
└── myfeature/
    └── screen.tsx  // No layout config!

Why it crashes: react-native-screens creates snapshots for transitions. Without proper config, snapshots fail on complex views (gradients, blurs, images).

DO THIS INSTEAD:

// app/myfeature/_layout.tsx
import { Stack } from 'expo-router';
import { Platform } from 'react-native';

export default function MyFeatureLayout() {
  return (
    <Stack
      screenOptions={{
        headerShown: false,
        freezeOnBlur: false,  // Prevent snapshot crashes
        animation: Platform.OS === 'ios' ? 'default' : 'slide_from_right',
      }}
    />
  );
}

Crash signature: RNSScreen setViewToSnapshot, snapshotViewAfterScreenUpdates


4. Loading Screens During Navigation

DON'T DO THIS:

export default function DeeplinkHandler() {
  const [loading, setLoading] = useState(true);

  return loading ? (
    <LoadingScreen />  // Creates snapshot, then redirects = crash
  ) : (
    <Redirect href="/target" />
  );
}

Why it crashes: Mounting a loading screen that immediately redirects causes snapshot creation mid-navigation.

DO THIS INSTEAD:

export default function DeeplinkHandler() {
  return <Redirect href="/target" />;  // Direct redirect, no snapshot
}

5. Component Props

DON'T DO THIS:

<MagicalLoadingScreen />  // Missing required prop!

Why it crashes: Component tries to access array with undefined key.

DO THIS INSTEAD:

<MagicalLoadingScreen context="character" />  // Proper context

Code Review Checklist

Before merging iOS-related code, verify:

  • No LinearGradient uses width: '100%' or height: '100%'
  • All LinearGradient styles have minWidth and/or minHeight
  • Navigation screens have transition={0} on expo-image components
  • All route directories have _layout.tsx with freezeOnBlur: false
  • No loading screens immediately before <Redirect>
  • All custom components have required props documented

Testing Requirements

Before deploying iOS changes:

  1. Test on physical device (not just simulator)
  2. Test deeplinks: Cold start (app closed) and warm start (background)
  3. Test navigation: Between multiple screens rapidly
  4. Test with slow network: Enable network conditioning
  5. Check crash logs: Use Xcode Organizer or TestFlight feedback

Quick Diagnostics

App crashes during navigation?

  1. Check for LinearGradient with width: '100%'
  2. Check for expo-image with transition > 0
  3. Check crash log for "CGContext" or "RNSScreen"
  1. Verify route has _layout.tsx
  2. Check for intermediate loading screens
  3. Test with direct <Redirect>

App crashes showing loading screen?

  1. Check component has all required props
  2. Verify arrays/objects aren't undefined
  3. Add null checks before array access

Common Error Messages

Error Message Likely Cause Solution
CGContextDrawLinearGradient LinearGradient invalid dimensions Use alignSelf: 'stretch' + minWidth
RNSScreen setViewToSnapshot Missing Stack config or complex view Add _layout.tsx with freezeOnBlur: false
image_finalize Image deallocated during render Disable transitions, add recycling key
Cannot convert undefined to object Missing prop or undefined array Add required props, null checks

Resources


Need Help?

If you encounter a crash not covered here:

  1. Get the full crash log from Xcode Organizer or TestFlight
  2. Identify the crash signature (function names in stack trace)
  3. Document reproduction steps (exact user actions)
  4. Check recent changes to navigation or layout code
  5. Add to this document once resolved!