A Swift/SwiftUI iOS app that lets people connect based on shared interests. Users store interests, tap phones to exchange profiles via NFC, and optionally pin the location where they met on a map. Includes a lightweight account flow, profile/interest management, connection tracking, and a map view of your network.
- Account flow: simple sign up / login with local persistence.
- Interests engine: Academic / Sports / Media categories (add/remove in-app).
- NFC exchange: Read/write NDEF payloads with shared interests (iPhone 7+).
- “Where we met”: Long-press to drop a pin and save GPS coordinates.
- Selfie on connect: Capture a quick photo when adding a connection.
- Connections list + leaderboard: Track who you’ve met and compare counts.
- Map of connections: See saved connections as MapKit annotations.
- All SwiftUI UI, with UIKit bridges where needed (NFC, Camera, Maps).
Frameworks: SwiftUI
, Combine
, UIKit
, CoreNFC
, CoreLocation
, MapKit
State: ObservableObject
+ @Published
(MVVM-ish, singletons for managers)
Persistence: UserDefaults
with Codable
models (per-user namespaced keys)
Spark/
├─ Models/
│ ├─ InterestsModel.swift // Codable; default categories + values
│ ├─ UserProfile.swift // Codable + Identifiable; interests, connections
│ └─ Connection.swift // Codable + Identifiable + Hashable
│ // custom encode/decode for CLLocationCoordinate2D
├─ Managers/
│ ├─ InterestsManager.swift // ObservableObject; persists per user
│ └─ UserManager.swift // ObservableObject; profiles, session, connections
├─ NFC/
│ ├─ NFCReaderViewController.swift // NFCNDEFReaderSessionDelegate
│ └─ NFCReaderViewRepresentable.swift // SwiftUI bridge (UIViewControllerRepresentable)
├─ UI/
│ ├─ SwiftUI views: SignUpLoginView, HomeView, MenuView, ...
│ ├─ InterestCategoryView / EditInterestsView / CategorySelectionView
│ ├─ ConnectionsView / LeaderboardView
│ ├─ ConnectionsMapView (Map + annotations)
│ ├─ ConnectionPromptView (sheet after NFC read)
│ ├─ ImagePicker (UIKit bridge)
│ └─ LocationPickerViewController (+ representable)
└─ App/
└─ ContentView.swift // root Nav + environment objects
InterestsModel
:{ academicInterests: [String], sportsInterests: [String], mediaInterests: [String] }
UserProfile
:username
,password
,bio
,interests
,[Connection]
Connection
:username
,date
,photo (Data?)
,location (CLLocationCoordinate2D?)
Username: <username>
Academic Interests: Math, Science
Sports Interests: Football, Basketball
Media Interests: Movies, Music
- Xcode 15+
- iOS 15+ (SwiftUI + UIKit bridges; NFC requires iPhone 7 or later)
- A physical iPhone for NFC testing (simulator does not support NFC)
git clone https://github.com/<your-org>/spark-ios.git
cd spark-ios
open Spark.xcodeproj
# Select a real iOS device target, then Build & Run
💡 NFC read/write requires a physical device and the “Near Field Communication Tag Reading” capability enabled.
Add the following to Signing & Capabilities:
- Near Field Communication Tag Reading
Add to Info.plist:
NFCReaderUsageDescription
= “Spark uses NFC to share interests with nearby users.”NSCameraUsageDescription
= “Spark uses the camera to attach a selfie when connecting.”NSLocationWhenInUseUsageDescription
= “Spark uses your location to pin where you met.”- (Optional)
NSPhotoLibraryAddUsageDescription
if you later allow saving images
- Sign Up / Login (
SignUpLoginView
) - Profile Home (
HomeView
)- View your bio + interest categories
- Tap NFC to read/write interests with another device
- NFC (
NFCReaderViewController
)- Starts
NFCNDEFReaderSession
- Reads or writes a structured, human-readable payload
- On success: parse →
ConnectionPromptView
- Starts
- Connect Prompt
- Optionally take a selfie (
UIImagePickerController
) - Pin location via
LocationPickerViewController
(Map long-press) - Save connection to the current user (
UserManager.addConnection
)
- Optionally take a selfie (
- Browse
- ConnectionsView: list + inline location/photo preview
- LeaderboardView: ranked by
connectionCount
- ConnectionsMapView: map annotations of pinned locations
- NFC: validate both read and write paths (multiple tags, timeout, user cancel).
- Models: round-trip encode/decode of
Connection
(including location) viaCodable
. - Persistence: ensure
UserDefaults
keys are namespaced by username and updated on edits. - Map: verify long-press adds an annotation and passes coordinates through the representable.
- Camera: confirm image capture → Data conversion → UI preview in the connect prompt.
- Per-user storage:
InterestsManager
stores interests underInterestsData_<username>
. - Profiles list persisted under
UserProfiles
viaUserManager.saveProfiles()
. - Error states: NFC errors (user cancel / timeout / unsupported tag) are surfaced with alerts.
- Replace
UserDefaults
with Cloud sync (e.g., CloudKit or Firestore). - Add nearby discovery (Bluetooth / MultipeerConnectivity) to complement NFC.
- Encrypted NFC payloads + verifiable profiles.
- Rich chat + shared media gallery per connection.
- App Clips / QR fallback when NFC unavailable.
- Fork and create a feature branch:
git checkout -b feat/short-title
- Commit with clear messages and small, focused changes
- Open a PR with a concise description and screenshots if UI changes
Code style: Swift 5, SwiftUI first; UIKit bridges where necessary; keep managers testable.
MIT License (add a LICENSE
file to your repo if you don’t already have one).
Replace with real captures from your device:
/Screenshots/
01-login.png
02-home.png
03-nfc-read.png
04-connection-prompt.png
05-map-pin.png
06-connections-list.png
07-leaderboard.png
-
Custom Codable for Coordinates
Connection
manually encodes/decodesCLLocationCoordinate2D
aslatitude
/longitude
to keep modelsCodable
. -
SwiftUI ↔ UIKit Bridges
NFCReaderViewControllerRepresentable
,LocationPickerViewControllerRepresentable
, andImagePicker
expose UIKit controllers into SwiftUI. -
Interest Editing UX
EditInterestsView
supports add/remove with immediate persistence; categories selected viaCategorySelectionView
. -
Leaderboard
Sorted byconnectionCount
derived property onUserProfile
.
- Build to two physical iPhones with
Near Field Communication Tag Reading
enabled. - On device A, go to Menu → Update NFC Tag to write your current interests.
- On device B, tap NFC button on Home and hold near device A.
- Accept the connect prompt → take selfie (optional) → pin location (optional) → Connect.
- Check Connections list and Map to verify new entry.