A comprehensive iOS Instagram clone built with SwiftUI. This project explores modern iOS development patterns, Firebase integration, and contemporary app architecture while building a fully functional social media app.
Core Technologies:
- SwiftUI - Declarative UI framework with iOS 17+ Observable architecture
- Firebase - Authentication, Firestore database, and Storage (SDK 12.1.0+)
- Swift Concurrency - Async/await patterns with MainActor
- Observation Framework - Modern reactive programming (replaces Combine)
- PhotosPicker - Native photo selection for iOS
This Instagram clone demonstrates modern iOS development through practical implementation. The app includes all the core features you'd expect from a social media platform - user authentication, real-time feeds, commenting, notifications, and user relationships.
The project focuses on:
- SwiftUI Framework for modern declarative UI development
- Firebase Integration for authentication, database, and cloud storage
- Real-time data synchronization using async/await patterns
- MVVM architecture with the new Observation framework
- Modern iOS features like PhotosPicker and NavigationStack
The app follows a clean MVVM architecture using SwiftUI and the new iOS 17+ Observation framework. Here's how it's structured:
SwiftUI + MVVM Architecture
- View Layer: SwiftUI views with declarative UI components using State and Bindable
- ViewModel Layer: Observable classes using iOS 17+ Observation framework (no Combine needed)
- Service Layer: Singleton Observable services for Firebase operations and data management
- Model Layer: Codable data models that work seamlessly with Firebase
Technology Stack
- SwiftUI for the entire user interface
- Firebase SDK 12.1.0 for backend services (Auth, Firestore, Storage)
- iOS 17+ Observation framework for reactive data binding
- PhotosPicker for native photo selection
- Async/Await for modern Swift concurrency
Registration Flow (Router-Driven)
- Uses
AuthenticationRouter(@Observable) to centralize multi-step onboarding. RegistrationSteps(Identifiable,Hashable) drivesNavigationStack(path:)destinations.- Views call
router.startRegistration()to begin androuter.navigate()to advance steps. LoginViewprovidesRegistrationViewModelandAuthenticationRoutervia environment and usesnavigationDestination(for:).- Real-time validation:
AddEmailViewandCreateUsernameViewvalidate uniqueness viaAuthManager.validateEmail()andvalidateUsername()before advancing to next step.
Error Handling
- Custom
AuthenticationErrorenum with Firebase error code mapping (17004-17026) - User-friendly localized error messages for all authentication failures
- ViewModels use
showErrorBoolean anderror: AuthenticationError?withdidSetobserver - Views present alerts automatically using
.alert("Oops!", isPresented: $viewModel.showError)
Example:
@State private var router = AuthenticationRouter()
NavigationStack(path: $router.navigationPath) {
// ... Login UI ...
}
.navigationDestination(for: RegistrationSteps.self) { step in
switch step {
case .email: AddEmailView()
case .username: CreateUsernameView()
case .password: CreatePasswordView()
case .completion: CompleteSighUpView()
}
}
// Start registration from LoginView
Button("Sign up") { router.startRegistration() }
// Advance step inside registration views
Button("Next") { router.navigate() }This isn't just a basic clone - it's a fully functional social media app with all the features you'd expect:
User Authentication & Profiles Complete user system with email/password registration, multi-step onboarding, and profile management. Users can upload profile pictures, edit their information, and view detailed statistics about their activity.
Social Features Full follow/unfollow system with real-time updates. Users can see their followers and following lists, discover new users through search, and view other profiles with complete post grids.
Posts & Feed Instagram-style feed with real-time loading, photo uploading via PhotosPicker, and complete interaction system. Users can like, unlike, and comment on posts with optimistic UI updates for smooth performance.
Real-time Notifications Comprehensive notification system that alerts users when someone likes their posts, comments, or follows them. Notifications are delivered in real-time with proper Firebase security rules.
Comments System Full commenting functionality with real-time updates. Comments appear instantly with optimistic UI while syncing to Firebase in the background.
Search & Discovery Real-time user search with live filtering and responsive results. The app includes some fun character profiles (Marvel characters) for demonstration purposes.
InstagramCloneTutorial/
βββ App/
β βββ InstagramCloneTutorialApp.swift # App entry point with Firebase configuration
βββ Core/
β βββ Authentication/ # Complete authentication system
β β βββ Error/AuthenticationError.swift # Custom error enum with Firebase error code mapping
β β βββ Service/AuthService.swift # Firebase Auth integration
β β βββ ViewModel/ # LoginViewModel, RegistrationViewModel
β β βββ View/ # Login, Registration flow screens
β βββ Routing/ # Registration flow routing
β β βββ AuthenticationRouter.swift # Observable router with navigationPath
β β βββ RegistrationSteps.swift # Step enum driving NavigationStack
β βββ Feed/ # Main timeline functionality
β β βββ View/FeedView.swift, FeedCell.swift # Feed UI components
β β βββ ViewModel/FeedViewModel.swift # Feed data management
β βββ Comments/ # Comments system
β β βββ Model/Comment.swift # Comment data model
β β βββ Service/CommentService.swift # Firebase comment operations
β β βββ View/CommentsView.swift, CommentsCell.swift # Comment UI components
β β βββ ViewModel/CommentViewModel.swift # Comment data management
β βββ Notifications/ # Real-time notifications system
β β βββ Model/ # IGNotification.swift, IGNotificationType.swift
β β βββ Service/NotificationsService.swift # Firebase notification operations
β β βββ Manager/NotificationManager.swift # Centralized notification management
β β βββ View/ # NotificationsView.swift, NotificationsCell.swift
β β βββ ViewModel/IGNotificationsViewModel.swift # Notification data management
β βββ Search/ # User discovery system
β β βββ View/SearchView.swift # Search interface
β β βββ ViewModel/SearchViewModel.swift # Search functionality
β βββ Profile/ # Complete profile system
β β βββ View/ # ProfileView, EditProfileView, ProfileHeaderView, etc.
β β βββ ViewModel/
β β βββ EditProfileViewModel.swift # Profile editing logic
β β βββ ProfileViewModel.swift # Profile data, follow/unfollow, stats management
β βββ UploadPosts/ # Post creation system
β β βββ View/UploadPostView.swift # Post upload interface
β β βββ ViewModel/UploadPostViewModel.swift # Upload functionality
β βββ Components/ # Reusable UI components
β β βββ View/CircularProfileImageView.swift # Profile image component
β β βββ View/PostGridView.swift # Post grid display
β β βββ View/UserStatView.swift # User statistics display
β β βββ View/UserListView.swift # User list component for followers/following
β β βββ ViewModel/PostGridViewModel.swift # Grid data management
β β βββ ViewModel/UserListViewModel.swift # User list data management
β βββ TabBar/MainTabView.swift # Main navigation container
β βββ Root/ # App root management
β βββ View/ContentView.swift # Root content view
β βββ ViewModel/ContentViewModel.swift # App state management
βββ Model/
β βββ User.swift # User data model with Firebase integration, follow status, and stats
β βββ Post.swift # Post data model with user linking
β βββ UserListConfig.swift # Configuration enum for different user list contexts
βββ Services/
β βββ UserService.swift # Singleton service for user data, follow/unfollow, and stats
β βββ PostService.swift # Post data operations
β βββ ImageUploader.swift # Firebase Storage image handling
βββ Extension/
β βββ Timestamp.swift # Firebase Timestamp extension for relative time formatting
βββ Utils/
β βββ Constants.swift # Firebase constants (users, posts, following, followers collections)
βββ Assets.xcassets/ # App icons and character images
βββ Screenshots/ # App screenshot collection
Firebase Integration
// Firebase constants for centralized collection references
struct FirebaseConstants {
static let Root = Firestore.firestore()
static let UsersCollection = Root.collection("users")
static let PostsCollection = Root.collection("posts")
static let FollowingCollection = Root.collection("following")
static let FollowersCollection = Root.collection("followers")
static let NotificationsCollection = Root.collection("notifications")
static func UserNotificationCollection(uid: String) -> CollectionReference {
return NotificationsCollection.document(uid).collection("user-notifications")
}
}
// Authentication with async/await and custom error handling
func createUser(email: String, password: String, username: String) async throws {
do {
let result = try await Auth.auth().createUser(withEmail: email, password: password)
await uploadUserData(uid: result.user.uid, username: username, email: email)
} catch {
let authErrorCode = AuthErrorCode(rawValue: (error as NSError).code)?.rawValue ?? -1
throw AuthenticationError(rawValue: authErrorCode)
}
}
// Custom AuthenticationError enum
enum AuthenticationError: Error {
case userDisabled
case emailAlreadyInUse
case invalidEmail
case wrongPassword
case userNotFound
case networkError
case credentialAlreadyInUse
case weakPassword
case unknownError
case invalidCredential
case tooManyRequests
init(rawValue: Int) {
switch rawValue {
case 17004: self = .invalidCredential // Modern Firebase error
case 17005: self = .userDisabled
case 17007: self = .emailAlreadyInUse
case 17008: self = .invalidEmail
case 17009: self = .wrongPassword
case 17010: self = .tooManyRequests
case 17011: self = .userNotFound
case 17020: self = .networkError
case 17025: self = .credentialAlreadyInUse
case 17026: self = .weakPassword
default: self = .unknownError
}
}
}
// ViewModel error handling pattern
@Observable
class LoginViewModel {
var email = ""
var password = ""
var showError = false
var error: AuthenticationError? {
didSet { showError = error != nil }
}
func login(with authManager: AuthManager) async {
do {
try await authManager.login(withEmail: email, password: password)
} catch let error as AuthenticationError {
self.error = error
} catch {
self.error = .unknownError
}
}
}
// View presents error alerts automatically
struct LoginView: View {
@State var loginViewModel = LoginViewModel()
var body: some View {
// ... UI components ...
.alert("Oops!", isPresented: $loginViewModel.showError) {
Text(loginViewModel.error?.localizedDescription ?? "Unknown error")
}
}
}
// Firestore data operations with centralized constants
func fetchAllUsers() async throws -> [User] {
let snapshot = try await FirebaseConstants.UsersCollection.getDocuments()
return snapshot.documents.compactMap({ try? $0.data(as: User.self) })
}
// Centralized user state management
UserService.shared.currentUser // Accessible throughout the app
// Follow/Unfollow operations
static func follow(uid: String) async throws {
// Creates subcollections in both following and followers collections
}
static func checkIfUserIsFollowed(uid: String) async throws -> Bool {
// Checks if current user follows the target user
}
// Fetch user statistics
static func fetchUserStats(uid: String) async throws -> UserStats {
// Returns following count, followers count, and posts count
}
// Relative timestamp formatting
extension Timestamp {
func timestampString() -> String {
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.second, .minute, .hour, .day, .weekOfMonth]
formatter.maximumUnitCount = 1
formatter.unitsStyle = .abbreviated
return formatter.string(from: self.dateValue(), to: Date()) ?? ""
}
}
// Notification system integration
class NotificationManager {
static let shared = NotificationManager()
private let service = NotificationsService()
func uploadLikeNotification(to uid: String, post: Post) async throws {
try await service.uploadNotification(toUid: uid, type: .like, post: post)
}
func uploadFollowNotification(to uid: String) async throws {
try await service.uploadNotification(toUid: uid, type: .follow)
}
func deleteLikeNotification(notificationOwner: String, post: Post) async {
// Automatically removes notification when user unlikes
}
}
// Real-time notification fetching
func fetchNotifications() async throws -> [IGNotification] {
let snapshot = try await FirebaseConstants
.UserNotificationCollection(uid: currentUid)
.order(by: "timestamp", descending: true)
.getDocuments()
return snapshot.documents.compactMap({ try? $0.data(as: IGNotification.self)})
}Modern SwiftUI Patterns (iOS 17+)
// @Observable replaces ObservableObject + @Published
@Observable
class FeedViewModel {
var posts = [Post]()
func fetchPosts() async throws {
// Modern async data loading
}
}
// Views use @State instead of @StateObject
struct FeedView: View {
@State private var viewModel = FeedViewModel()
var body: some View {
ForEach(viewModel.posts) { post in
FeedCell(post: post)
}
}
}
// @Bindable enables two-way binding with @Observable
struct EditProfileView: View {
@State private var viewModel: EditProfileViewModel
var body: some View {
@Bindable var viewModel = viewModel
TextField("Name", text: $viewModel.fullname)
}
}Reactive State Management
// Singleton @Observable services for centralized state
@Observable
class AuthService {
var userSession: FirebaseAuth.User?
static let shared = AuthService()
}
@Observable
class UserService {
var currentUser: User?
static let shared = UserService()
}
// Views automatically observe @Observable properties
struct ContentView: View {
@State var viewModel = ContentViewModel()
var body: some View {
if viewModel.userSession == nil {
LoginView()
} else if let currentUser = viewModel.currentUser {
MainTabView(user: currentUser)
}
}
}What you'll need:
- Xcode 16.4 or later
- iOS 18.5+ deployment target
- A Firebase project (free to set up)
Setup:
- Clone this repository
- Open
InstagramCloneTutorial.xcodeprojin Xcode - Set up Firebase:
- Create a new Firebase project at Firebase Console
- Download your
GoogleService-Info.plistfile and add it to the project root - Update the bundle ID to match your Firebase project
- Enable Authentication and Firestore in the Firebase Console
- Build and run
Important: The
GoogleService-Info.plistfile is gitignored for security. You'll need to add your own Firebase configuration file.
Firebase Setup: The app uses three Firebase services:
- FirebaseAuth for user authentication
- FirebaseFirestore for the database
- FirebaseStorage for image uploads
Building this Instagram clone covers a lot of ground in modern iOS development:
- Modern iOS Development with SwiftUI and the new Observable framework
- Firebase Integration for real-time apps with authentication and database operations
- Swift Concurrency using async/await patterns and MainActor for UI updates
- MVVM Architecture using Observable classes instead of Combine
- State Management with SwiftUI's State, Bindable, and Environment
- Real-world UI/UX patterns that feel native to iOS
This is a fully functional Instagram clone with all core features implemented. The app includes user authentication, profiles, posting, commenting, following, real-time notifications, and search functionality. Everything is built using modern iOS patterns and the latest SwiftUI features.
What's working: Everything! The app is feature-complete with user auth, posts, comments, follows, notifications, and search.
Future ideas:
- Push notifications when the app is closed
- Stories functionality
- Direct messaging
- Image filters and editing tools
- Better image caching and performance optimization
This project demonstrates concepts from modern iOS development, including SwiftUI patterns, Firebase integration, and Swift concurrency. It's a practical example of building a real-world social media app with contemporary tools and patterns.
This project demonstrates modern iOS development patterns and is designed for educational purposes.



