iOS / Swift 8 min read Updated Aug 2026

Building a Native iOS 4K Wallpaper App in Swift & SwiftUI with AsyncImage

Step-by-step iOS native guide using Swift 5.9, SwiftUI, URLSession, and AsyncImage to build a liquid-smooth wallpaper app with dark mode support.

1. Swift Codable Model for Wallpapers

Create a Swift model to decode the NexWall 4K JSON payload with type safety:

import Foundation

struct WallpaperItem: Identifiable, Codable {
    let id: Int
    let categoryId: Int
    let imageUrl: String
    let thumbnailUrl: String
    let isPremium: Bool
    let resolution: String
    
    enum CodingKeys: String, CodingKey {
        case id
        case categoryId = "category_id"
        case imageUrl = "image_url"
        case thumbnailUrl = "thumbnail_url"
        case isPremium = "is_premium"
        case resolution
    }
}

struct WallpaperResponse: Codable {
    let success: Bool
    let data: [WallpaperItem]
}

2. URLSession Network Service

import Foundation

class WallpaperAPIService: ObservableObject {
    @Published var wallpapers: [WallpaperItem] = []
    @Published var isLoading = false
    
    private let apiKey = "YOUR_NEXWALL_API_KEY"
    
    func fetchWallpapers(page: Int = 1) async {
        guard let url = URL(string: "https://nexwall.kodnextech.com/api/developer/v1/wallpapers?page=\(page)&per_page=30") else { return }
        
        var request = URLRequest(url: url)
        request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
        request.setValue("application/json", forHTTPHeaderField: "Accept")
        
        do {
            let (data, _) = try await URLSession.shared.data(for: request)
            let decoded = try JSONDecoder().decode(WallpaperResponse.self, from: data)
            DispatchQueue.main.async {
                self.wallpapers = decoded.data
                self.isLoading = false
            }
        } catch {
            print("Fetch error: \(error)")
        }
    }
}

3. SwiftUI Staggered Grid with AsyncImage

import SwiftUI

struct WallpaperGridView: View {
    @StateObject var api = WallpaperAPIService()
    let columns = [GridItem(.flexible(), spacing: 12), GridItem(.flexible(), spacing: 12)]
    
    var body: some View {
        NavigationView {
            ScrollView {
                LazyVGrid(columns: columns, spacing: 12) {
                    ForEach(api.wallpapers) { item in
                        AsyncImage(url: URL(string: item.thumbnailUrl)) { image in
                            image.resizable()
                                 .aspectRatio(9/16, contentMode: .fill)
                                 .clipped()
                                 .cornerRadius(14)
                        } placeholder: {
                            Color(white: 0.15).aspectRatio(9/16, contentMode: .fit)
                        }
                    }
                }
                .padding()
            }
            .background(Color.black.edgesIgnoringSafeArea(.all))
            .navigationTitle("4K Wallpapers")
            .task {
                await api.fetchWallpapers()
            }
        }
    }
}

Want to test this endpoint right now?

Use the interactive Live Sandbox Console to test queries without writing code.

Try In Sandbox