This guide provides detailed instructions for setting up and developing the Interspace iOS application.
- Environment Setup
- Project Configuration
- Development Workflow
- API Integration
- Testing
- Debugging
- Performance Optimization
- Troubleshooting
- macOS: Version 13.0 (Ventura) or later
- Xcode: Version 15.0 or later
# Check Xcode version xcodebuild -version - Command Line Tools:
xcode-select --install
- CocoaPods:
sudo gem install cocoapods pod --version # Should be 1.12.0+
-
Clone the repository:
git clone https://github.com/interspace/interspace-ios.git cd interspace-ios -
Install dependencies:
pod install
-
Copy configuration templates:
# Create configuration files from templates cp Interspace/Supporting/BuildConfiguration.xcconfig.template Interspace/Supporting/BuildConfiguration.xcconfig cp Interspace/GoogleService-Info.plist.template Interspace/GoogleService-Info.plist cp .env.example .env cp .xcode.env.local.template .xcode.env.local
-
Google OAuth Configuration:
- Go to Google Cloud Console
- Create a new project or select existing
- Enable Google Sign-In API
- Create OAuth 2.0 credentials (iOS)
- Add your bundle identifier
- Download configuration and update
GoogleService-Info.plist
-
Infura Configuration:
- Sign up at Infura
- Create a new project
- Copy the Project ID
- Add to
BuildConfiguration.xcconfig:INFURA_API_KEY = your_infura_project_id_here
-
WalletConnect Configuration:
- Register at WalletConnect Cloud
- Create a new project
- Copy the Project ID
- Add to
BuildConfiguration.xcconfig:WALLETCONNECT_PROJECT_ID = your_walletconnect_project_id_here
The project supports three build configurations:
-
Debug: For local development
- API URLs point to local/development servers
- Debug logging enabled
- Assertions active
-
Staging: For testing
- API URLs point to staging servers
- Limited logging
- Performance monitoring
-
Release: For production
- API URLs point to production servers
- Minimal logging
- Optimizations enabled
Edit .xcode.env.local with your local configuration:
# Node.js path (if using React Native bridges)
export NODE_BINARY=/usr/local/bin/node
# API Keys
export INFURA_API_KEY=your_infura_key_here
export WALLETCONNECT_PROJECT_ID=your_walletconnect_id_here
# API URLs
export API_BASE_URL_DEBUG=http://localhost:3000/api/v1
export API_BASE_URL_RELEASE=https://api.interspace.com/api/v1Interspace/
├── Models/ # Data models and business logic
├── Views/ # SwiftUI views
├── ViewModels/ # View models (MVVM pattern)
├── Services/ # API and business services
├── Extensions/ # Swift extensions
├── Components/ # Reusable UI components
└── Supporting/ # Configuration and resources
-
Create the model (if needed):
// Models/Feature.swift struct Feature: Codable, Identifiable { let id: String let name: String // ... properties }
-
Create the service:
// Services/FeatureService.swift class FeatureService { func fetchFeatures() async throws -> [Feature] { // Implementation } }
-
Create the view model:
// ViewModels/FeatureViewModel.swift @MainActor class FeatureViewModel: ObservableObject { @Published var features: [Feature] = [] @Published var isLoading = false private let service = FeatureService() func loadFeatures() async { isLoading = true defer { isLoading = false } do { features = try await service.fetchFeatures() } catch { // Handle error } } }
-
Create the view:
// Views/FeatureView.swift struct FeatureView: View { @StateObject private var viewModel = FeatureViewModel() var body: some View { // View implementation } }
-
View Composition:
struct ContentView: View { var body: some View { VStack { HeaderView() MainContent() FooterView() } } }
-
State Management:
// Local state @State private var isPresented = false // Observed object @ObservedObject var viewModel: MyViewModel // Environment object @EnvironmentObject var session: SessionManager
-
Modifiers:
Text("Hello") .font(.headline) .foregroundColor(.primary) .padding() .background(Color.secondary.opacity(0.1)) .cornerRadius(8)
-
Using APIService:
let response: MyResponse = try await APIService.shared.request( endpoint: "endpoint/path", method: .POST, body: myRequestBody )
-
Error Handling:
do { let data = try await apiService.fetchData() // Handle success } catch APIError.unauthorized { // Handle unauthorized } catch APIError.networkError { // Handle network error } catch { // Handle other errors }
-
Login:
try await AuthService.shared.login( email: email, password: password )
-
Token Management:
- Tokens are automatically stored in Keychain
- Automatic token refresh on 401 responses
- Token included in all authenticated requests
-
Create test file:
// InterspaceTests/FeatureTests.swift import XCTest @testable import Interspace final class FeatureTests: XCTestCase { func testFeatureCreation() { let feature = Feature(id: "1", name: "Test") XCTAssertEqual(feature.name, "Test") } }
-
Run tests:
# Command line xcodebuild test -workspace Interspace.xcworkspace -scheme Interspace # Or in Xcode Cmd+U
- Create UI test:
// InterspaceUITests/FeatureUITests.swift func testFeatureFlow() { let app = XCUIApplication() app.launch() // Test implementation }
Use the DevelopmentWalletService for testing wallet functionality without real blockchain connections.
-
SwiftUI Preview:
struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() .previewDevice("iPhone 15 Pro") .preferredColorScheme(.dark) } }
-
Debug Overlay:
- Enable in Settings → Developer Options
- Shows environment, API calls, and performance metrics
-
Network Debugging:
// Enable in AppDelegate URLSession.shared.configuration.waitsForConnectivity = true
// Use built-in logging
print("🔍 Debug: \(message)")
print("⚠️ Warning: \(message)")
print("❌ Error: \(error)")
// Or use os_log for production
import os.log
let logger = Logger(subsystem: "com.interspace", category: "Feature")
logger.debug("Debug message")-
Use AsyncImage for remote images:
AsyncImage(url: URL(string: imageURL)) { image in image .resizable() .aspectRatio(contentMode: .fit) } placeholder: { ProgressView() }
-
Cache images:
// Images are automatically cached by URLSession
-
Use LazyVStack/LazyVGrid:
ScrollView { LazyVStack { ForEach(items) { item in ItemView(item: item) } } }
-
Implement proper Identifiable:
struct Item: Identifiable { let id = UUID() // Stable identifier }
-
Pod Installation Fails:
# Clean and reinstall pod deintegrate pod install -
Build Errors:
# Clean build folder rm -rf ~/Library/Developer/Xcode/DerivedData # Or in Xcode: Shift+Cmd+K
-
Simulator Issues:
- Reset simulator: Device → Erase All Content and Settings
- Try different simulator device
-
Signing Issues:
- Ensure valid Apple Developer account
- Check bundle identifier matches
- Update provisioning profiles
-
API Response Issues:
- Check network logs in console
- Verify API endpoint URLs
- Check authentication tokens
-
UI Layout Issues:
- Use SwiftUI Inspector (Cmd+Click on view)
- Check constraint warnings
- Test on different device sizes
-
Performance Issues:
- Use Instruments for profiling
- Check for retain cycles
- Optimize image loading