Swift
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Optionals
-
Section 4: Object-Oriented and Value Types
-
Section 5: Memory Management
-
Section 6: Generics and Error Handling
-
Section 7: Concurrency
-
Section 8: Working with Collections
-
Section 9: Codable and Data Handling
-
Section 10: Protocol-Oriented Programming
-
Section 11: Testing and Tooling
-
Section 12: Practical Projects
-
Section 13: Interview Practice
-
Section 14: More Practice Exercises
-
Section 15: More Standard Library
-
Section 16: Advanced Concurrency
-
Section 17: Foundation Framework Deep Dive
-
Section 18: URLSession and Networking Deep Dive
-
Section 19: Combine Framework
-
Section 20: SwiftUI Fundamentals for Swift Developers
-
Section 21: Server-Side Swift with Vapor
-
Section 22: Swift Package Manager Deep Dive
-
Section 23: Swift Concurrency Deep Dive
-
Section 24: More Language Features
-
Section 25: Error Handling Deep Dive
-
Section 26: Testing Deep Dive
-
Section 27: Data Structures and Algorithms in Swift
-
Section 28: More Practice Exercises
-
Section 29: More Interview Practice
-
Section 30: Swift Macros (Swift 5.9+)
-
Section 31: Property Wrappers Ecosystem
-
Section 32: Swift Interop Deep Dive
-
Section 33: iOS App Architecture Patterns
-
Section 34: Performance and Debugging
-
Section 35: App Distribution and CI/CD
-
Section 36: More Practical Projects
-
Section 37: SwiftData and Persistence
-
Section 38: More Design Patterns
-
Section 39: More Review and Practice
-
Section 40: More Foundation Deep Dive
-
Section 41: Advanced Collections in Swift
-
Section 42: Advanced Generics Practice
-
Section 43: UIKit for Legacy and Hybrid Apps
-
Section 44: watchOS and visionOS Development Basics
-
Section 45: More Networking Patterns
-
Section 46: More Testing Practice
-
Section 47: Accessibility in Swift Apps
-
Section 48: Localization
-
Section 49: More Practical Projects Round 2
-
Section 50: Swift Charts Framework
-
Section 51: More Interview and Algorithm Practice
-
Section 52: Final Practice and Mastery
-
Section 53: Swift Compiler and Build System
-
Section 54: More Concurrency Practice
-
Section 55: App Store Guidelines and Review
-
Section 56: More Design and Architecture
193: Spatial Computing Concepts in visionOS
I remember the first time I jumped into visionOS development. I spent about an hour staring at a blank screen, convinced my code was broken because my 3D model simply wouldn't appear. I had written the RealityView perfectly, the asset was loaded, and there were no crashes in the console. I just... saw nothing.
struct SpatialView: View {
var body: some View {
RealityView { content in
if let model = try? await Entity.load(named: "Robot") {
// I just want it to appear right in front of me!
model.position = [0, 0, 0]
content.add(model)
}
}
}
}
The Invisible Model Mystery
The bug here is a classic "spatial" mistake. In a traditional 2D app, (0,0) is the top-left corner of your screen. In visionOS, the origin (0,0,0) is the center of the user's head. By setting the position to zero, I had effectively spawned my robot inside my own skull. Because the camera (the user's eyes) cannot see geometry that is clipping through the near-plane of the view, the model was invisible.
When you're working in spatial computing, you have to stop thinking in pixels and start thinking in meters. In RealityKit, 1 unit equals 1 meter. If you put something at [0, 0, 0], you're putting it exactly where the user is standing.
Pushing Content into the Living Room
To fix this, we need to move the entity along the Z-axis. In the visionOS coordinate system, negative Z is forward. If you want an object to appear in front of the user, you move it away from the origin in the negative direction.
struct SpatialView: View {
var body: some View {
RealityView { content in
if let model = try? await Entity.load(named: "Robot") {
// Move it 1.5 meters away from the user
// X: 0 (center), Y: 0 (eye level), Z: -1.5 (forward)
model.position = [0, 0, -1.5]
content.add(model)
}
}
}
}
Now the robot is sitting comfortably in the room. I usually recommend starting with a distance of 1.5 to 2.0 meters. Anything closer than 0.5 meters feels claustrophobic and can cause visual discomfort for the user; anything further than 5 meters starts to feel disconnected from the interaction.
Managing Windows vs. Immersive Spaces
It's also important to remember that where you place your RealityView matters. If you put it inside a standard WindowGroup, the "world" is relative to that window's position in space. The window itself is a 2D plane floating in a 3D world. When you add a 3D entity to a window's RealityView, the (0,0,0) origin is the center of that window, not the user's head.
However, once you move into an ImmersiveSpace, you're dealing with the "World Space." Here, the user is the center of the universe. This is where coordinate precision becomes critical. If you're building a game or a simulation, you'll likely spend more time managing these transforms than actually writing logic. I've found that creating a small "Debug Sphere" (a simple 10cm sphere) and placing it at known coordinates is the fastest way to orient yourself when your main assets are acting up.
The Logic of Spatial Transforms
One thing that trips people up is the difference between position and transform. While position is a convenient shorthand for moving something, the Transform object handles rotation and scale as well. In spatial computing, rotation is handled via quaternions (which are a headache to calculate manually), so I highly suggest using the simd_quatf helpers or the Transform convenience methods to rotate your objects to face the user.
📋 Practical Task
Exercise: Building a Spatial Floating Dashboard
Your goal is to create a RealityView that simulates a basic dashboard. Instead of one object, you need to place three different 3D primitives (a sphere, a box, and a cylinder) in a semi-circle in front of the user.
- The Layout:
- Place the Sphere 1.5 meters directly in front of the user (Center).
- Place the Box 1.5 meters in front, but 0.7 meters to the left.
- Place the Cylinder 1.5 meters in front, but 0.7 meters to the right.
- The Constraints: All objects must be at a Y-height of 0 (eye level) to ensure they don't appear on the floor or ceiling.
- The Challenge: Ensure you are using the correct Z-axis polarity so that the objects appear in the room, not behind the user's head.
Hint: Use MeshResource.generateSphere(radius:) and ModelEntity to create the shapes since you don't have external assets.
There are no comments for now.