15 Prompts for Swift and iOS: SwiftUI, UIKit, Core Data, and Combine

{
"title": "15 Prompts for Swift and iOS: SwiftUI, UIKit, Core Data, and Combine",
"content": "## Introduction\n\nBuilding iOS applications in 2026 is more streamlined than ever, thanks to the maturity of SwiftUI, the flexibility of UIKit, the persistence power of Core Data, and the reactive capabilities of Combine. However, even experienced developers often struggle to craft the perfect prompt for AI-assisted coding tools like ChatGPT, GitHub Copilot, or Claude. A well-structured prompt can save hours of debugging and boilerplate writing.\n\nThis article presents 15 carefully curated prompts for iOS development, organized into four categories: SwiftUI, UIKit, Core Data, and Combine. Each prompt includes the exact text to use, a practical example scenario, and the resulting code. Whether you are a junior developer looking to speed up your workflow or a senior architect refining your team's AI usage, these prompts will help you get precise, production-ready output.\n\nAccording to a 2025 Stack Overflow survey, over 40% of developers now use AI tools daily for code generation. By mastering prompt engineering for iOS-specific tasks, you can significantly reduce development time and improve code quality.\n\n## Category 1: SwiftUI Prompts\n\n### 1. Building a Dynamic List with Search and Filter\n\nTask: Create a SwiftUI view that displays a list of items fetched from a local JSON file, with a search bar and category filter.\n\nPrompt:\n\nGenerate a SwiftUI view named ContentView that loads a list of 'Book' objects from a local 'books.json' file. Each book has fields: id, title, author, genre, and year. Display the list using a NavigationStack with a searchable modifier that filters by title or author. Add a Picker above the list to filter by genre. Show the book title and author in each row. Use MVVM architecture with an ObservableObject view model. Include error handling for missing or malformed JSON.\n\n\nExample Result:\n```swift\nimport SwiftUI\n\nstruct Book: Codable, Identifiable {\n let id: Int\n let title: String\n let author: String\n let genre: String\n let year: Int\n}\n\nclass BookViewModel: ObservableObject {\n @Published var books: [Book] = []\n @Published var searchText = \"\"\n @Published var selectedGenre: String = \"All\"\n \n var filteredBooks: [Book] {\n books.filter { book in\n let matchesSearch = searchText.isEmpty

||\n book.title.localizedCaseInsensitiveContains(searchText) ||\n book.author.localizedCaseInsensitiveContains(searchText)\n let matchesGenre = selectedGenre == \"All\" || book.genre == selectedGenre\n return matchesSearch && matchesGenre\n }\n }\n \n var genres: [String] {\n let all = Set(books.map { $0.genre })\n return [\"All\"] + all.sorted()\n }\n \n func loadBooks() {\n guard let url = Bundle.main.url(forResource: \"books\", withExtension: \"json\") else {\n print(\"JSON file not found\")\n return\n }\n do {\n let data = try Data(contentsOf: url)\n let decoded = try JSONDecoder().decode([Book].self, from: data)\n DispatchQueue.main.async {\n self.books = decoded\n }\n } catch {\n print(\"Failed to load books: \(error.localizedDescription)\")\n }\n }\n}\n\nstruct ContentView: View {\n @StateObject private var viewModel = BookViewModel()\n \n var body: some View {\n NavigationStack {\n VStack {\n Picker(\"Genre\", selection: $viewModel.selectedGenre) {\n ForEach(viewModel.genres, id: \.self) { genre in\n Text(genre).tag(genre)\n }\n }\n .pickerStyle(.segmented)\n .padding(.horizontal)\n \n List(viewModel.filteredBooks) { book in\n VStack(alignment: .leading) {\n Text(book.title).font(.headline)\n Text(book.author).font(.subheadline).foregroundColor(.secondary)\n }\n }\n }\n .searchable(text: $viewModel.searchText, prompt: \"Search by title or author\")\n .navigationTitle(\"Books\")\n .onAppear {\n viewModel.loadBooks()\n }\n }\n }\n}\n\n\n**Explanation**: This prompt covers essential SwiftUI patterns: loading data from a bundle, using `@StateObject`, combining `searchable` with `Picker`, and following MVVM. The output is immediately usable in a real project.\n\n### 2. Creating a Custom Animated Transition\n\n**Task**: Implement a custom transition between two views using matched geometry effect and custom animation.\n\n**Prompt**:\n\nWrite a SwiftUI view that shows a grid of thumbnail images. When the user taps a thumbnail, transition to a detail view using matchedGeometryEffect with a hero animation. The thumbnail should expand to fill the screen, showing the full image with a title and description. Use a namespace for the animation and support both landscape and portrait orientations. Add a close button that reverses the transition.\n\n\n**Example Result**:\nswift\nimport SwiftUI\n\nstruct HeroView: View {\n @Namespace private var animation\n @State private var selectedItem: Int?\n \n let items = [\n (id: 1, name: \"Sunset\", image: \"sunset\"),\n (id: 2, name: \"Mountains\", image: \"mountains\"),\n (id: 3, name: \"Ocean\", image: \"ocean\")\n ]\n \n var body: some View {\n NavigationStack {\n ScrollView {\n LazyVGrid(columns: [GridItem(.adaptive(minimum: 100))]) {\n ForEach(items, id: \.id) { item in\n Image(item.image)\n .resizable()\n .scaledToFill()\n .frame(width: 100, height: 100)\n .clipShape(RoundedRectangle(cornerRadius: 10))\n .matchedGeometryEffect(id: item.id, in: animation)\n .onTapGesture {\n withAnimation(.spring(response: 0.6, dampingFraction: 0.8)) {\n selectedItem = item.id\n }\n }\n }\n }\n .padding()\n }\n .navigationTitle(\"Gallery\")\n .overlay {\n if let id = selectedItem, let item = items.first(where: { $0.id == id }) {\n Color.black.opacity(0.4).ignoresSafeArea()\n VStack {\n Image(item.image)\n .resizable()\n .scaledToFit()\n .matchedGeometryEffect(id: item.id, in: animation)\n .overlay(alignment: .topTrailing) {\n Button(\"Close\") {\n withAnimation(.spring(response: 0.6, dampingFraction: 0.8)) {\n selectedItem = nil\n }\n }\n .padding()\n }\n Text(item.name).font(.title).foregroundColor(.white)\n }\n }\n }\n }\n }\n}\n\n\n**Explanation**: The prompt specifies the need for `matchedGeometryEffect`, namespace, and a spring animation. The output demonstrates a complete hero transition with adaptive grid layout and proper state management.\n\n### 3. Form with Validation and Custom Styles\n\n**Task**: Build a registration form with text fields, pickers, and real-time validation.\n\n**Prompt**:\n\nCreate a SwiftUI registration form with fields: username, email, password, and a date picker for birth date. Add real-time validation: username must be at least 3 characters, email must contain '@', password must be at least 8 characters with one uppercase letter and one number. Show validation errors inline below each field. Style the form with a custom background, rounded text fields, and a gradient submit button that is disabled until all fields are valid. Use @FocusState to manage keyboard navigation.\n\n\n**Example Result**:\nswift\nimport SwiftUI\n\nstruct RegistrationForm: View {\n @State private var username = \"\"\n @State private var email = \"\"\n @State private var password = \"\"\n @State private var birthDate = Date()\n @FocusState private var focusedField: Field?\n \n enum Field: Hashable {\n case username, email, password\n }\n \n var isFormValid: Bool {\n username.count >= 3 &&\n email.contains(\"@\") &&\n password.count >= 8 &&\n password.rangeOfCharacter(from: .uppercaseLetters) != nil &&\n password.rangeOfCharacter(from: .decimalDigits) != nil\n }\n \n var body: some View {\n NavigationStack {\n VStack(spacing: 20) {\n Text(\"Create Account\")\n .font(.largeTitle).bold()\n \n VStack(alignment: .leading) {\n TextField(\"Username\", text: $username)\n .focused($focusedField, equals: .username)\n .textFieldStyle(.roundedBorder)\n .autocapitalization(.none)\n if username.count > 0 && username.count < 3 {\n Text(\"Username must be at least 3 characters\")\n .foregroundColor(.red).font(.caption)\n }\n }\n \n VStack(alignment: .leading) {\n TextField(\"Email\", text: $email)\n .focused($focusedField, equals: .email)\n .textFieldStyle(.roundedBorder)\n .keyboardType(.emailAddress)\n .autocapitalization(.none)\n if email.count > 0 && !email.contains(\"@\") {\n Text(\"Email must contain '@'\")\n .foregroundColor(.red).font(.caption)\n }\n }\n \n VStack(alignment: .leading) {\n SecureField(\"Password\", text: $password)\n .focused($focusedField, equals: .password)\n .textFieldStyle(.roundedBorder)\n if password.count > 0 && (password.count < 8 ||\n password.rangeOfCharacter(from: .uppercaseLetters) == nil ||\n password.rangeOfCharacter(from: .decimalDigits) == nil) {\n Text(\"Password must be 8+ chars, 1 uppercase, 1 digit\")\n .foregroundColor(.red).font(.caption)\n }\n }\n \n DatePicker(\"Birth Date\", selection: $birthDate, displayedComponents: .date)\n \n Button(\"Register\") {\n // Handle registration\n }\n .frame(maxWidth: .infinity)\n .padding()\n .background(isFormValid ? LinearGradient(colors: [.blue, .purple], startPoint: .leading, endPoint: .trailing) : LinearGradient(colors: [.gray], startPoint: .leading, endPoint: .trailing))\n .foregroundColor(.white)\n .clipShape(Capsule())\n .disabled(!isFormValid)\n }\n .padding()\n .background(Color(.systemGroupedBackground))\n .navigationTitle(\"Sign Up\")\n .toolbar {\n ToolbarItemGroup(placement: .keyboard) {\n Button(\"Next\") {\n switch focusedField {\n case .username: focusedField = .email\n case .email: focusedField = .password\n case .password: focusedField = nil\n case .none: break\n }\n }\n }\n }\n }\n }\n}\n\n\n**Explanation**: This prompt produces a production-ready form with `@FocusState` for keyboard navigation, inline validation messages, and a disabled submit button. The gradient styling adds polish.\n\n## Category 2: UIKit Prompts\n\n### 4. Programmatic UICollectionView with Diffable Data Source\n\n**Task**: Set up a UICollectionView using modern diffable data source and compositional layout.\n\n**Prompt**:\n\nCreate a UIViewController that contains a UICollectionView with a compositional layout. The collection view should display items in a grid of 3 columns on portrait and 5 columns on landscape. Use UICollectionViewDiffableDataSource to manage the data. The data is an array of 'Photo' objects with id and imageName. Support cell registration with a custom UICollectionViewCell that shows the image and a label. Implement pull-to-refresh that simulates loading new data.\n\n\n**Example Result**:\nswift\nimport UIKit\n\nstruct Photo: Hashable {\n let id: Int\n let imageName: String\n}\n\nclass PhotoCell: UICollectionViewCell {\n static let reuseIdentifier = \"PhotoCell\"\n \n private let imageView = UIImageView()\n private let label = UILabel()\n \n override init(frame: CGRect) {\n super.init(frame: frame)\n setupViews()\n }\n \n required init?(coder: NSCoder) { fatalError() }\n \n private func setupViews() {\n imageView.contentMode = .scaleAspectFill\n imageView.clipsToBounds = true\n label.textAlignment = .center\n label.font = UIFont.systemFont(ofSize: 12)\n \n let stack = UIStackView(arrangedSubviews: [imageView, label])\n stack.axis = .vertical\n stack.translatesAutoresizingMaskIntoConstraints = false\n contentView.addSubview(stack)\n NSLayoutConstraint.activate([\n stack.topAnchor.constraint(equalTo: contentView.topAnchor),\n stack.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),\n stack.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),\n stack.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)\n ])\n }\n \n func configure(with photo: Photo) {\n imageView.image = UIImage(named: photo.imageName)\n label.text = \"Photo \(photo.id)\"\n }\n}\n\nclass GalleryViewController: UIViewController {\n private var collectionView: UICollectionView!\n private var dataSource: UICollectionViewDiffableDataSource!\n private var photos = (1...20).map { Photo(id: $0, imageName: \"photo_\($0)\") }\n \n override func viewDidLoad() {\n super.viewDidLoad()\n setupCollectionView()\n configureDataSource()\n applySnapshot()\n }\n \n private func setupCollectionView() {\n let layout = UICollectionViewCompositionalLayout { , environment in\n let width = environment.container.effectiveContentSize.width\n let columns = width > 500 ? 5 : 3\n let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0 / CGFloat(columns)), heightDimension: .fractionalHeight(1.0))\n let item = NSCollectionLayoutItem(layoutSize: itemSize)\n let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(150))\n let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])\n let section = NSCollectionLayoutSection(group: group)\n section.interGroupSpacing = 4\n return section\n }\n \n collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)\n collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]\n collectionView.register(PhotoCell.self, forCellWithReuseIdentifier: PhotoCell.reuseIdentifier)\n collectionView.refreshControl = UIRefreshControl()\n collectionView.refreshControl?.addTarget(self, action: #selector(refreshData), for: .valueChanged)\n view.addSubview(collectionView)\n }\n \n private func configureDataSource() {\n dataSource = UICollectionViewDiffableDataSource(collectionView: collectionView) { collectionView, indexPath, photo in\n let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PhotoCell.reuseIdentifier, for: indexPath) as! PhotoCell\n cell.configure(with: photo)\n return cell\n }\n }\n \n private func applySnapshot(animating: Bool = true) {\n var snapshot = NSDiffableDataSourceSnapshot()\n snapshot.appendSections([0])\n snapshot.appendItems(photos)\n dataSource.apply(snapshot, animatingDifferences: animating)\n }\n \n @objc private func refreshData() {\n DispatchQueue.main.asyncAfter(deadline: .now() + 1) {\n self.photos = (21...40).map { Photo(id: $0, imageName: \"photo\($0)\") }\n self.applySnapshot()\n self.collectionView.refreshControl?.endRefreshing()\n }\n }\n}\n\n\n**Explanation**: This prompt demonstrates modern UIKit patterns: compositional layout, diffable data source, and pull-to-refresh. The output adapts to device orientation and is fully programmatic, avoiding storyboards.\n\n### 5. Custom UIViewController Transition Animation\n\n**Task**: Implement a custom modal presentation animation.\n\n**Prompt**:\n\nWrite a UIViewControllerAnimatedTransitioning class that presents a view controller modally with a custom slide-up and bounce animation. The presented view controller should slide up from the bottom with a damping spring effect. Dismissal should slide it back down. Additionally, create a UIPresentationController that adds a dimming view behind the presented controller. The presented view should have rounded top corners and a corner radius of 20.\n\n\n**Example Result**:\nswift\nimport UIKit\n\nclass SlideUpTransitionAnimator: NSObject, UIViewControllerAnimatedTransitioning {\n let isPresenting: Bool\n \n init(isPresenting: Bool) {\n self.isPresenting = isPresenting\n }\n \n func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {\n return 0.6\n }\n \n func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {\n guard let toView = transitionContext.view(forKey: .to) else { return }\n let container = transitionContext.containerView\n \n if isPresenting {\n container.addSubview(toView)\n toView.frame.origin.y = container.frame.height\n UIView.animate(\n withDuration: transitionDuration(using: transitionContext),\n delay: 0,\n usingSpringWithDamping: 0.7,\n initialSpringVelocity: 0.5,\n options: .curveEaseInOut,\n animations: {\n toView.frame.origin.y = 0\n },\n completion: { finished in\n transitionContext.completeTransition(!transitionContext.transitionWasCancelled)\n }\n )\n } else {\n UIView.animate(\n withDuration: transitionDuration(using: transitionContext),\n animations: {\n toView.frame.origin.y = container.frame.height\n },\n completion: { finished in\n toView.removeFromSuperview()\n transitionContext.completeTransition(!transitionContext.transitionWasCancelled)\n }\n )\n }\n }\n}\n\nclass CustomPresentationController: UIPresentationController {\n private lazy var dimmingView: UIView = {\n let view = UIView()\n view.backgroundColor = UIColor.black.withAlphaComponent(0.5)\n view.alpha = 0\n return view\n }()\n \n override func presentationTransitionWillBegin() {\n guard let containerView = containerView else { return }\n dimmingView.frame = containerView.bounds\n containerView.insertSubview(dimmingView, at: 0)\n \n presentedViewController.transitionCoordinator?.animate(alongsideTransition: { _ in\n self.dimmingView.alpha = 1\n })\n }\n \n override func dismissalTransitionWillBegin() {\n presentedViewController.transitionCoordinator?.animate(alongsideTransition: { _ in\n self.dimmingView.alpha = 0\n })\n }\n \n override var presentedView: UIView? {\n let view = super.presentedView\n view?.layer.cornerRadius = 20\n view?.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]\n view?.clipsToBounds = true\n return view\n }\n}\n\n// Usage in presenting view controller:\n// let vc = ModalViewController()\n// vc.modalPresentationStyle = .custom\n// vc.transitioningDelegate = self\n// present(vc, animated: true)\n\n\n**Explanation**: This prompt covers custom transitions and presentation controllers. The output includes a spring animation and dimming overlay, commonly used for bottom sheets.\n\n### 6. Dynamic TableView with Multiple Cell Types\n\n**Task**: Build a table view that renders different cell types based on data model.\n\n**Prompt**:\n\nCreate a UITableViewController that displays a feed with three types of cells: a text post, an image post, and a video post. Use a single data source array of a 'FeedItem' enum with associated values. Register three different UITableViewCell subclasses. Implement automatic cell height using UITableView.automaticDimension. Each cell should have a unique identifier and configure itself based on the associated data. Add a pull-to-refresh feature.\n\n\n**Example Result**:\nswift\nimport UIKit\n\nenum FeedItem {\n case text(content: String, author: String)\n case image(imageName: String, caption: String)\n case video(url: String, duration: TimeInterval)\n}\n\nclass TextPostCell: UITableViewCell {\n static let reuseIdentifier = \"TextPostCell\"\n private let contentLabel = UILabel()\n private let authorLabel = UILabel()\n \n override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {\n super.init(style: style, reuseIdentifier: reuseIdentifier)\n setupViews()\n }\n \n required init?(coder: NSCoder) { fatalError() }\n \n private func setupViews() {\n contentLabel.numberOfLines = 0\n authorLabel.font = UIFont.boldSystemFont(ofSize: 14)\n let stack = UIStackView(arrangedSubviews: [authorLabel, contentLabel])\n stack.axis = .vertical\n stack.translatesAutoresizingMaskIntoConstraints = false\n contentView.addSubview(stack)\n NSLayoutConstraint.activate([\n stack.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8),\n stack.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),\n stack.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),\n stack.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8)\n ])\n }\n \n func configure(with item: FeedItem) {\n if case .text(let content, let author) = item {\n contentLabel.text = content\n authorLabel.text = author\n }\n }\n}\n\nclass ImagePostCell: UITableViewCell {\n static let reuseIdentifier = \"ImagePostCell\"\n private let postImageView = UIImageView()\n private let captionLabel = UILabel()\n \n override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {\n super.init(style: style, reuseIdentifier: reuseIdentifier)\n setupViews()\n }\n \n required init?(coder: NSCoder) { fatalError() }\n \n private func setupViews() {\n postImageView.contentMode = .scaleAspectFill\n postImageView.clipsToBounds = true\n postImageView.heightAnchor.constraint(equalToConstant: 200).isActive = true\n captionLabel.numberOfLines = 0\n let stack = UIStackView(arrangedSubviews: [postImageView, captionLabel])\n stack.axis = .vertical\n stack.translatesAutoresizingMaskIntoConstraints = false\n contentView.addSubview(stack)\n NSLayoutConstraint.activate([\n stack.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8),\n stack.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),\n stack.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),\n stack.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8)\n ])\n }\n \n func configure(with item: FeedItem) {\n if case .image(let imageName, let caption) = item {\n postImageView.image = UIImage(named: imageName)\n captionLabel.text = caption\n }\n }\n}\n\nclass VideoPostCell: UITableViewCell {\n static let reuseIdentifier = \"VideoPostCell\"\n private let thumbnailView = UIImageView()\n private let durationLabel = UILabel()\n \n override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {\n super.init(style: style, reuseIdentifier: reuseIdentifier)\n setupViews()\n }\n \n required init?(coder: NSCoder) { fatalError() }\n \n private func setupViews() {\n thumbnailView.contentMode = .scaleAspectFill\n thumbnailView.clipsToBounds = true\n thumbnailView.heightAnchor.constraint(equalToConstant: 150).isActive = true\n durationLabel.textAlignment = .center\n let stack = UIStackView(arrangedSubviews: [thumbnailView, durationLabel])\n stack.axis = .vertical\n stack.translatesAutoresizingMaskIntoConstraints = false\n contentView.addSubview(stack)\n NSLayoutConstraint.activate([\n stack.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8),\n stack.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),\n stack.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),\n stack.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8)\n ])\n }\n \n func configure(with item: FeedItem) {\n if case .video(let url, let duration) = item {\n thumbnailView.image = UIImage(named: \"video_placeholder\")\n durationLabel.text = \"Duration: \(Int(duration))s\"\n }\n }\n}\n\nclass FeedViewController: UITableViewController {\n var feedItems: [FeedItem] = []\n \n override func viewDidLoad() {\n super.viewDidLoad()\n tableView.register(TextPostCell.self, forCellReuseIdentifier: TextPostCell.reuseIdentifier)\n tableView.register(ImagePostCell.self, forCellReuseIdentifier: ImagePostCell.reuseIdentifier)\n tableView.register(VideoPostCell.self, forCellReuseIdentifier: VideoPostCell.reuseIdentifier)\n tableView.rowHeight = UITableView.automaticDimension\n tableView.estimatedRowHeight = 100\n tableView.refreshControl = UIRefreshControl()\n tableView.refreshControl?.addTarget(self, action: #selector(refreshFeed), for: .valueChanged)\n loadSampleData()\n }\n \n private func loadSampleData() {\n feedItems = [\n .text(content: \"Hello World!\", author: \"Alice\"),\n .image(imageName: \"photo1\", caption: \"A beautiful sunset\"),\n .video(url: \"video1.mp4\", duration: 120)\n ]\n tableView.reloadData()\n }\n \n @objc private func refreshFeed() {\n DispatchQueue.main.asyncAfter(deadline: .now() + 1) {\n self.tableView.refreshControl?.endRefreshing()\n }\n }\n \n override func tableView( tableView: UITableView, numberOfRowsInSection section: Int) -> Int {\n return feedItems.count\n }\n \n override func tableView( tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {\n let item = feedItems[indexPath.row]\n switch item {\n case .text:\n let cell = tableView.dequeueReusableCell(withIdentifier: TextPostCell.reuseIdentifier, for: indexPath) as! TextPostCell\n cell.configure(with: item)\n return cell\n case .image:\n let cell = tableView.dequeueReusableCell(withIdentifier: ImagePostCell.reuseIdentifier, for: indexPath) as! ImagePostCell\n cell.configure(with: item)\n return cell\n case .video:\n let cell = tableView.dequeueReusableCell(withIdentifier: VideoPostCell.reuseIdentifier, for: indexPath) as! VideoPostCell\n cell.configure(with: item)\n return cell\n }\n }\n}\n\n\n**Explanation**: This prompt handles heterogeneous table views with different cell layouts. The enum-based approach keeps the data model clean, and automatic cell dimensions ensure proper sizing.\n\n## Category 3: Core Data Prompts\n\n### 7. Setting Up Core Data Stack with CloudKit Sync\n\n**Task**: Create a Core Data stack with NSPersistentCloudKitContainer for iCloud sync.\n\n**Prompt**:\n\nGenerate a Core Data stack using NSPersistentCloudKitContainer. Include a shared singleton called PersistenceController. The container should have two configurations: a local configuration for sensitive data that does not sync, and a cloud configuration that syncs with iCloud. Provide functions to save context with error handling, and a preview context for SwiftUI previews with in-memory store. Use a lazy initialization pattern.\n\n\n**Example Result**:\nswift\nimport CoreData\n\nstruct PersistenceController {\n static let shared = PersistenceController()\n \n let container: NSPersistentCloudKitContainer\n \n init(inMemory: Bool = false) {\n container = NSPersistentCloudKitContainer(name: \"MyApp\")\n \n if inMemory {\n container.persistentStoreDescriptions.first?.url = URL(fileURLWithPath: \"/dev/null\")\n } else {\n // Cloud configuration\n let cloudStoreURL = FileManager.default\n .containerURL(forSecurityApplicationGroupIdentifier: \"group.com.myapp\")!\n .appendingPathComponent(\"CloudStore.sqlite\")\n let cloudDescription = NSPersistentStoreDescription(url: cloudStoreURL)\n cloudDescription.configuration = \"Cloud\"\n cloudDescription.cloudKitContainerOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: \"iCloud.com.myapp\")\n \n // Local configuration\n let localStoreURL = FileManager.default\n .urls(for: .documentDirectory, in: .userDomainMask).first!\n .appendingPathComponent(\"LocalStore.sqlite\")\n let localDescription = NSPersistentStoreDescription(url: localStoreURL)\n localDescription.configuration = \"Local\"\n \n container.persistentStoreDescriptions = [cloudDescription, localDescription]\n }\n \n container.loadPersistentStores { _, error in\n if let error = error as NSError? {\n fatalError(\"Unresolved error \(error), \(error.userInfo)\")\n }\n }\n container.viewContext.automaticallyMergesChangesFromParent = true\n container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy\n }\n \n func save() {\n let context = container.viewContext\n if context.hasChanges {\n do {\n try context.save()\n } catch {\n let nsError = error as NSError\n print(\"Save error: \(nsError), \(nsError.userInfo)\")\n }\n }\n }\n \n static var preview: PersistenceController = {\n let controller = PersistenceController(inMemory: true)\n let viewContext = controller.container.viewContext\n for i in 0..<10 {\n let item = Item(context: viewContext)\n item.timestamp = Date()\n item.name = \"Sample \(i)\"\n }\n try? viewContext.save()\n return controller\n }()\n}\n\n\n**Explanation**: This prompt covers advanced Core Data setup with CloudKit sync, multiple configurations, and preview support. It follows Apple's recommended patterns from WWDC sessions.\n\n### 8. Fetching and Displaying Data with NSFetchedResultsController\n\n**Task**: Implement a table view backed by Core Data with real-time updates.\n\n**Prompt**:\n\nWrite a UITableViewController that uses NSFetchedResultsController to display a list of 'Task' entities. The Task entity has attributes: title (String), priority (Int16), dueDate (Date), and isCompleted (Bool). Sort by priority descending, then dueDate ascending. Filter out completed tasks. The table should update automatically when data changes. Support swipe-to-delete and a toggle to mark tasks as completed. Use a custom cell that shows a checkbox and the title.\n\n\n**Example Result**:\nswift\nimport UIKit\nimport CoreData\n\nclass TaskCell: UITableViewCell {\n static let reuseIdentifier = \"TaskCell\"\n var onToggle: (() -> Void)?\n \n private let checkboxButton = UIButton(type: .system)\n private let titleLabel = UILabel()\n \n override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {\n super.init(style: style, reuseIdentifier: reuseIdentifier)\n setupViews()\n }\n \n required init?(coder: NSCoder) { fatalError() }\n \n private func setupViews() {\n checkboxButton.addTarget(self, action: #selector(toggleTapped), for: .touchUpInside)\n titleLabel.numberOfLines = 0\n let stack = UIStackView(arrangedSubviews: [checkboxButton, titleLabel])\n stack.spacing = 8\n stack.translatesAutoresizingMaskIntoConstraints = false\n contentView.addSubview(stack)\n NSLayoutConstraint.activate([\n stack.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8),\n stack.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),\n stack.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),\n stack.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8)\n ])\n }\n \n func configure(with task: Task) {\n titleLabel.text = task.title\n let imageName = task.isCompleted ? \"checkmark.circle.fill\" : \"circle\"\n checkboxButton.set

← All posts

Comments