Swift Macros: Vi du thuc te ve metaprogramming
Huong dan day du ve Swift Macros: tao macro freestanding va attached bao gom body macro Swift 6, thao tac AST voi swift-syntax, kem vi du thuc te giup loai bo ma lap.

Swift Macros thay doi cach cac nha phat trien viet va bao tri ma nguon. Duoc gioi thieu voi Swift 5.9 va mo rong dang ke trong Swift 6, macro cho phep sinh ma tai thoi diem bien dich trong khi van dam bao an toan kieu tinh. Khac voi macro cua bo tien xu ly C, Swift Macros an toan ve kieu, tich hop trong trinh bien dich va duoc cong cu phat trien ho tro day du bao gom tinh nang "Expand Macro" cua Xcode.
Huong dan nay tim hieu viec tao Swift Macros tu cac khai niem co ban den cac trien khai nang cao, bao gom body macro moi duoc gioi thieu trong Swift 6 (SE-0415). Tat ca vi du su dung Swift 6 va swift-syntax 600.0.0+.
Hieu cac loai Swift Macros
Swift cung cap hai nhom macro chinh, moi nhom phu hop voi nhung tinh huong su dung khac nhau. Macro freestanding hoat dong doc lap nhu bieu thuc hoac khai bao, trong khi macro attached gan voi mot khai bao co san de chinh sua hoac bo sung.
Macro freestanding: bieu thuc va khai bao
Macro freestanding bat dau bang ky hieu # va co the tra ve mot gia tri (bieu thuc) hoac tao cac khai bao moi. Duoi day la vi du cu the ve macro bieu thuc:
// Freestanding expression macro - generates a value
let buildInfo = #buildDate
// Expansion → "2026-08-23 10:30:45"
// Freestanding macro with arguments
let message = #stringify(1 + 2)
// Expansion → "1 + 2 = 3"
// Freestanding declaration macro - creates declarations
#makeCase("success", "failure", "pending")
// Expansion →
// case success
// case failure
// case pendingKhac biet cot loi giua bieu thuc va khai bao nam o ket qua: bieu thuc tao ra mot gia tri, con khai bao tao ra ma mang tinh cau truc (kieu, ham, bien).
Macro attached: sau vai tro
Macro attached bat dau bang @ va dat truoc mot khai bao. Swift 6 quy dinh sau vai tro khac nhau cho cac macro nay, bao gom vai tro body moi cho viec trien khai ham:
// @attached(peer) - adds declarations at the same level
@AddAsync
func fetchUser(id: Int) -> User { ... }
// Expansion → adds func fetchUserAsync(id: Int) async -> User
// @attached(accessor) - adds getters/setters
@UserDefault("theme")
var currentTheme: String
// Expansion → adds get { UserDefaults.standard.string(...) }
// @attached(member) - adds members to a type
@AutoEquatable
struct Point {
var x: Int
var y: Int
}
// Expansion → adds static func == (lhs: Point, rhs: Point) -> Bool
// @attached(memberAttribute) - applies attributes to members
@CodableKeys
struct Config {
var apiUrl: String
var timeout: Int
}
// Expansion → adds @CodingKey("api_url") before apiUrl
// @attached(extension) - adds protocol conformances
@Hashable
struct User {
var id: Int
var name: String
}
// Expansion → adds extension User: Hashable { ... }
// @attached(body) - NEW in Swift 6: synthesizes function bodies
@Remote
func fetchData(endpoint: String) -> Data
// Expansion → generates the entire function implementationCac vai tro nay co the duoc ket hop de tao ra macro manh me, bien doi ma tren nhieu khia canh cung luc.
Swift 6 Body Macros: SE-0415
Swift 6 gioi thieu function body macros thong qua SE-0415, cho phep macro tong hop hoac thay the cac trien khai ham. Dieu nay giai quyet cac truong hop ma khong vai tro macro truoc do nao co the xu ly.
Giao thuc BodyMacro
Giao thuc BodyMacro cho phep thay the hoan toan body ham:
import SwiftSyntax
import SwiftSyntaxMacros
public protocol BodyMacro: AttachedMacro {
static func expansion(
of node: AttributeSyntax,
providingBodyFor declaration: some DeclSyntaxProtocol &
WithOptionalCodeBlockSyntax,
in context: some MacroExpansionContext
) throws -> [CodeBlockItemSyntax]
}Macro nhan khai bao goc va tra ve cac item khoi ma tro thanh body ham. Body hien co se bi thay the.
Trien khai Remote Procedure Call Macro
Body macro dac biet huu ich de sinh ma tang network tu chu ky ham:
import SwiftSyntax
import SwiftSyntaxMacros
public struct RemoteMacro: BodyMacro {
public static func expansion(
of node: AttributeSyntax,
providingBodyFor declaration: some DeclSyntaxProtocol &
WithOptionalCodeBlockSyntax,
in context: some MacroExpansionContext
) throws -> [CodeBlockItemSyntax] {
guard let funcDecl = declaration.as(FunctionDeclSyntax.self) else {
throw MacroError.invalidSyntax("@Remote requires a function")
}
let functionName = funcDecl.name.text
let parameters = funcDecl.signature.parameterClause.parameters
// Generate parameter encoding
let paramDict = parameters.map { param in
let name = param.firstName.text
return "\"\(name)\": \(name)"
}.joined(separator: ", ")
// Generate the RPC body
return [
"""
let params: [String: Any] = [\(raw: paramDict)]
return try await RPCClient.shared.call(
method: "\(raw: functionName)",
params: params
)
"""
]
}
}Khai bao va su dung
/// Generates a remote procedure call implementation
@attached(body)
public macro Remote() = #externalMacro(
module: "MyMacrosPlugin",
type: "RemoteMacro"
)class APIService {
@Remote
func createUser(name: String, email: String) async throws -> User
@Remote
func deleteUser(id: UUID) async throws -> Bool
// Each function body is generated at compile time:
// func createUser(name: String, email: String) async throws -> User {
// let params: [String: Any] = ["name": name, "email": email]
// return try await RPCClient.shared.call(
// method: "createUser",
// params: params
// )
// }
}Chi co the ap dung toi da mot body macro cho mot ham. De composable preamble injection (logging, tracing), giao thuc PreambleMacro dang duoc xem xet cho cac phien ban Swift tuong lai.
Thiet lap du an de tao macro
Viec tao Swift Macros yeu cau mot Swift Package co cau truc cu the. Goi phu thuoc vao swift-syntax, thu vien chinh thuc de thao tac ma Swift duoi dang cay cu phap truu tuong (AST).
Cau truc Package.swift
// swift-tools-version: 6.0
import PackageDescription
let package = Package(
name: "MyMacros",
platforms: [.macOS(.v10_15), .iOS(.v13)],
products: [
// Library exposing macros to the main project
.library(
name: "MyMacros",
targets: ["MyMacros"]
),
// Executable for testing macros
.executable(
name: "MyMacrosClient",
targets: ["MyMacrosClient"]
)
],
dependencies: [
// Required dependency for macros - use 600.0.0+ for Swift 6
.package(
url: "https://github.com/swiftlang/swift-syntax.git",
from: "600.0.0"
)
],
targets: [
// Compiler plugin containing implementation
.macro(
name: "MyMacrosPlugin",
dependencies: [
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
.product(name: "SwiftCompilerPlugin", package: "swift-syntax")
]
),
// Target exposing macro declarations
.target(
name: "MyMacros",
dependencies: ["MyMacrosPlugin"]
),
// Test client
.executableTarget(
name: "MyMacrosClient",
dependencies: ["MyMacros"]
),
// Unit tests
.testTarget(
name: "MyMacrosTests",
dependencies: [
"MyMacrosPlugin",
.product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax")
]
)
]
)Cau hinh nay tach bach ro rang phan khai bao macro (ma ma phia client thay) khoi phan trien khai (chay luc bien dich).
Can it nhat ba tep: MyMacros.swift cho khai bao, MyMacrosPlugin.swift cho trien khai, va MyMacrosTests.swift cho kiem thu. Cach tach nay giup bao tri de dang hon.
Tao macro bieu thuc
Macro bieu thuc tao ra mot gia tri co the dung ngay trong ma. Sau day la cach tao macro #unwrap de mo gia tri optional kem thong bao loi tuy bien chua ten bien. De biet them ve cac mau xu ly loi Swift, xem huong dan ve Swift structured concurrency.
Khai bao macro
import Foundation
/// Macro that unwraps an optional with an explicit error message
/// Usage: let value = #unwrap(optionalValue)
/// Expansion: guard let optionalValue else { fatalError("...") }; optionalValue
@freestanding(expression)
public macro unwrap<T>(_ value: T?) -> T = #externalMacro(
module: "MyMacrosPlugin",
type: "UnwrapMacro"
)Chu ky khai bao cho biet macro nhan mot optional va tra ve gia tri non-optional. #externalMacro tro toi phan trien khai trong plugin.
Trien khai bang swift-syntax
import SwiftSyntax
import SwiftSyntaxMacros
import SwiftCompilerPlugin
public struct UnwrapMacro: ExpressionMacro {
public static func expansion(
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) throws -> ExprSyntax {
// Get the first argument passed to the macro
guard let argument = node.argumentList.first?.expression else {
throw MacroError.missingArgument
}
// Extract the variable name for the error message
let variableName = argument.description.trimmingCharacters(
in: .whitespacesAndNewlines
)
// Generate the expansion code
// Uses an immediately-invoked closure to encapsulate the guard
return """
{
guard let value = \(argument) else {
fatalError("Failed to unwrap '\\(\(literal: variableName))' - value was nil")
}
return value
}()
"""
}
}
// Custom errors for macros
enum MacroError: Error, CustomStringConvertible {
case missingArgument
case invalidSyntax(String)
var description: String {
switch self {
case .missingArgument:
return "The macro requires an argument"
case .invalidSyntax(let message):
return "Invalid syntax: \(message)"
}
}
}Phuong thuc expansion nhan node AST dai dien cho loi goi macro cung ngu canh bien dich, sau do tra ve ExprSyntax chua ma duoc sinh.
Dang ky plugin
import SwiftCompilerPlugin
import SwiftSyntaxMacros
@main
struct MyMacrosPlugin: CompilerPlugin {
// List all macros provided by this plugin
let providingMacros: [Macro.Type] = [
UnwrapMacro.self,
RemoteMacro.self,
AutoInitMacro.self,
// Add other macros here
]
}Diem vao nay thong bao cho trinh bien dich ve cac macro ma plugin cung cap.
Sẵn sàng chinh phục phỏng vấn iOS?
Luyện tập với mô phỏng tương tác, flashcards và bài kiểm tra kỹ thuật.
Tao macro attached kieu member
Macro member them thanh vien (thuoc tinh, phuong thuc, kieu long) vao mot kieu hien co. Sau day la macro @AutoInit tu dong tao bo khoi tao bao gom moi stored property.
Khai bao va trien khai day du
/// Automatically generates an initializer with all stored properties
@attached(member, names: named(init))
public macro AutoInit() = #externalMacro(
module: "MyMacrosPlugin",
type: "AutoInitMacro"
)import SwiftSyntax
import SwiftSyntaxMacros
public struct AutoInitMacro: MemberMacro {
public static func expansion(
of node: AttributeSyntax,
providingMembersOf declaration: some DeclGroupSyntax,
in context: some MacroExpansionContext
) throws -> [DeclSyntax] {
// Verify the macro is applied to a struct or class
guard declaration.is(StructDeclSyntax.self) ||
declaration.is(ClassDeclSyntax.self) else {
throw MacroError.invalidSyntax(
"@AutoInit can only be applied to structs and classes"
)
}
// Collect stored properties
let properties = declaration.memberBlock.members
.compactMap { $0.decl.as(VariableDeclSyntax.self) }
.filter { isStoredProperty($0) }
// Generate initializer parameters
let parameters = properties.compactMap { property -> String? in
guard let binding = property.bindings.first,
let identifier = binding.pattern.as(IdentifierPatternSyntax.self),
let type = binding.typeAnnotation?.type else {
return nil
}
let name = identifier.identifier.text
let typeName = type.description.trimmingCharacters(in: .whitespaces)
// Check if the property has a default value
if binding.initializer != nil {
return "\(name): \(typeName) = \(binding.initializer!.value)"
}
return "\(name): \(typeName)"
}
// Generate assignments in the init body
let assignments = properties.compactMap { property -> String? in
guard let binding = property.bindings.first,
let identifier = binding.pattern.as(IdentifierPatternSyntax.self) else {
return nil
}
let name = identifier.identifier.text
return "self.\(name) = \(name)"
}
// Build the complete initializer
let initDecl: DeclSyntax = """
public init(\(raw: parameters.joined(separator: ", "))) {
\(raw: assignments.joined(separator: "\n "))
}
"""
return [initDecl]
}
// Check if a variable is a stored property (not computed)
private static func isStoredProperty(_ variable: VariableDeclSyntax) -> Bool {
guard let binding = variable.bindings.first else { return false }
// A computed property has an accessor block with get/set
if let accessor = binding.accessorBlock {
// If it's a block with explicit accessors, it's computed
if accessor.accessors.is(AccessorDeclListSyntax.self) {
return false
}
}
// let or var without accessor = stored property
return true
}
}Su dung macro AutoInit
@AutoInit
struct User {
let id: UUID
var name: String
var email: String
var isActive: Bool = true
}
// Automatically generated code:
// public init(id: UUID, name: String, email: String, isActive: Bool = true) {
// self.id = id
// self.name = name
// self.email = email
// self.isActive = isActive
// }
// Usage
let user = User(id: UUID(), name: "Alice", email: "alice@example.com")
// isActive uses the default valueMacro nay loai bo boilerplate cho bo khoi tao, dac biet huu ich voi mo hinh du lieu co nhieu thuoc tinh.
Macro attached peer cho viec sinh phien ban async
Macro peer them cac khai bao cung cap voi khai bao duoc chu thich. Duoi day la macro @AddAsync sinh ra phien ban async cua mot ham dung completion handler. Mau nay dac biet phu hop khi chuyen doi ma networking cu, nhu da de cap trong huong dan chuyen doi Combine vs async/await.
/// Automatically generates an async version of a function with completion handler
@attached(peer, names: suffixed(Async))
public macro AddAsync() = #externalMacro(
module: "MyMacrosPlugin",
type: "AddAsyncMacro"
)import SwiftSyntax
import SwiftSyntaxMacros
public struct AddAsyncMacro: PeerMacro {
public static func expansion(
of node: AttributeSyntax,
providingPeersOf declaration: some DeclSyntax,
in context: some MacroExpansionContext
) throws -> [DeclSyntax] {
// Verify it's a function
guard let funcDecl = declaration.as(FunctionDeclSyntax.self) else {
throw MacroError.invalidSyntax(
"@AddAsync requires a function"
)
}
let functionName = funcDecl.name.text
let asyncFunctionName = "\(functionName)Async"
// Analyze parameters to find the completion handler
let parameters = funcDecl.signature.parameterClause.parameters
// Filter parameters (exclude completion handler)
var regularParams: [String] = []
var completionType: String? = nil
for param in parameters {
let paramType = param.type.description
// Detect a completion handler (closure with Result or simple value)
if paramType.contains("->") && paramType.contains("Void") {
// Extract the return type from completion
completionType = extractCompletionReturnType(from: paramType)
} else {
let paramName = param.firstName.text
let paramSecondName = param.secondName?.text
let label = paramSecondName ?? paramName
regularParams.append("\(paramName): \(paramType)")
}
}
guard let returnType = completionType else {
throw MacroError.invalidSyntax(
"No completion handler found"
)
}
// Generate arguments for internal call
let callArgs = parameters.dropLast().map { param in
let name = param.firstName.text
return "\(name): \(name)"
}.joined(separator: ", ")
// Generate the async function
let asyncFunc: DeclSyntax = """
func \(raw: asyncFunctionName)(\(raw: regularParams.joined(separator: ", "))) async throws -> \(raw: returnType) {
try await withCheckedThrowingContinuation { continuation in
\(raw: functionName)(\(raw: callArgs.isEmpty ? "" : callArgs + ", ")completion: { result in
switch result {
case .success(let value):
continuation.resume(returning: value)
case .failure(let error):
continuation.resume(throwing: error)
}
})
}
}
"""
return [asyncFunc]
}
// Extract return type from a Result type
private static func extractCompletionReturnType(from type: String) -> String {
// Simplified pattern - in production, use the AST
if let match = type.range(of: #"Result<([^,]+)"#, options: .regularExpression) {
var result = String(type[match])
result = result.replacingOccurrences(of: "Result<", with: "")
return result.trimmingCharacters(in: .whitespaces)
}
return "Void"
}
}Minh hoa macro AddAsync
class NetworkService {
@AddAsync
func fetchUser(
id: Int,
completion: @escaping (Result<User, Error>) -> Void
) {
// Implementation with callback
URLSession.shared.dataTask(with: URL(string: "/users/\(id)")!) { data, _, error in
if let error = error {
completion(.failure(error))
} else if let data = data {
let user = try? JSONDecoder().decode(User.self, from: data)
completion(.success(user!))
}
}.resume()
}
// Automatically generates:
// func fetchUserAsync(id: Int) async throws -> User {
// try await withCheckedThrowingContinuation { continuation in
// fetchUser(id: id, completion: { result in
// switch result {
// case .success(let value):
// continuation.resume(returning: value)
// case .failure(let error):
// continuation.resume(throwing: error)
// }
// })
// }
// }
}
// Modern usage with async/await
let user = try await networkService.fetchUserAsync(id: 42)Ten ham duoc sinh phai duoc khai bao trong names: cua thuoc tinh @attached. O day, suffixed(Async) cho biet ham sinh ra se them hau to "Async" vao ten goc.
Kiem thu don vi cho macro
Kiem thu macro la bat buoc boi macro tao ra ma se duoc bien dich sau do. Swift cung cap SwiftSyntaxMacrosTestSupport de ho tro nhung bai kiem thu nhu vay. Tu swift-syntax 603.0.0+, Swift Testing cung duoc ho tro cung voi XCTest.
import SwiftSyntaxMacros
import SwiftSyntaxMacrosTestSupport
import XCTest
@testable import MyMacrosPlugin
final class MyMacrosTests: XCTestCase {
// Dictionary of macros to test
let testMacros: [String: Macro.Type] = [
"unwrap": UnwrapMacro.self,
"AutoInit": AutoInitMacro.self,
"AddAsync": AddAsyncMacro.self,
"Remote": RemoteMacro.self
]
func testUnwrapMacroExpansion() throws {
assertMacroExpansion(
"""
let value = #unwrap(optionalString)
""",
expandedSource: """
let value = {
guard let value = optionalString else {
fatalError("Failed to unwrap 'optionalString' - value was nil")
}
return value
}()
""",
macros: testMacros
)
}
func testAutoInitMacroWithStruct() throws {
assertMacroExpansion(
"""
@AutoInit
struct Point {
let x: Int
var y: Int
}
""",
expandedSource: """
struct Point {
let x: Int
var y: Int
public init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
""",
macros: testMacros
)
}
func testAutoInitWithDefaultValues() throws {
assertMacroExpansion(
"""
@AutoInit
struct Config {
var timeout: Int = 30
var retryCount: Int
}
""",
expandedSource: """
struct Config {
var timeout: Int = 30
var retryCount: Int
public init(timeout: Int = 30, retryCount: Int) {
self.timeout = timeout
self.retryCount = retryCount
}
}
""",
macros: testMacros
)
}
func testAutoInitFailsOnEnum() throws {
assertMacroExpansion(
"""
@AutoInit
enum Status {
case active
}
""",
expandedSource: """
enum Status {
case active
}
""",
diagnostics: [
DiagnosticSpec(
message: "@AutoInit can only be applied to structs and classes",
line: 1,
column: 1
)
],
macros: testMacros
)
}
func testRemoteMacroExpansion() throws {
assertMacroExpansion(
"""
@Remote
func fetchUser(id: Int) async throws -> User
""",
expandedSource: """
func fetchUser(id: Int) async throws -> User {
let params: [String: Any] = ["id": id]
return try await RPCClient.shared.call(
method: "fetchUser",
params: params
)
}
""",
macros: testMacros
)
}
}Cac bai kiem thu kiem tra viec mo rong ma dung dan cung nhu nhung thong bao loi thich hop khi macro bi dung sai.
Go loi va kiem tra macro
Xcode cung cap nhieu cong cu de go loi macro va hieu ro ma duoc tao ra.
Mo rong trong Xcode
// Right-click on macro call → "Expand Macro"
// Displays generated code inline
@AutoInit
struct Product {
let id: UUID
var name: String
var price: Decimal
}
// To see the expansion:
// 1. Right-click on @AutoInit
// 2. Select "Expand Macro"
// 3. Generated code displays inline for inspection and debuggingGhi nhat ky trong qua trinh phat trien
public struct DebugMacro: ExpressionMacro {
public static func expansion(
of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext
) throws -> ExprSyntax {
// Print the node's AST to understand the structure
print("=== DEBUG MACRO ===")
print("Node: \(node)")
print("Arguments: \(node.argumentList)")
// Complete dump of the syntax tree
dump(node)
// Continue with normal expansion
return "42"
}
}Kham pha AST voi swift-ast-explorer
Cong cu truc tuyen swift-ast-explorer.com hien thi cay cu phap cho bat ky doan ma Swift nao. Hieu cau truc cac node AST la dieu can thiet khi trien khai macro, nhu da trinh bay trong huong dan framework Swift Testing de cap den cac testing macro tich hop san trong Swift.
Thuc hanh tot voi Swift Macros
Viec tao macro de bao tri doi hoi tuan thu mot so quy uoc va tranh cac bay pho bien.
Xac thuc va thong bao loi
public struct ValidatedMacro: MemberMacro {
public static func expansion(
of node: AttributeSyntax,
providingMembersOf declaration: some DeclGroupSyntax,
in context: some MacroExpansionContext
) throws -> [DeclSyntax] {
// Validate usage context
guard declaration.is(StructDeclSyntax.self) else {
// Clear error messages with possible localization
context.diagnose(
Diagnostic(
node: node,
message: MacroDiagnosticMessage(
id: "invalid-target",
message: "This macro can only be applied to structs",
severity: .error
)
)
)
return []
}
// Check required arguments
guard let arguments = node.arguments else {
context.diagnose(
Diagnostic(
node: node,
message: MacroDiagnosticMessage(
id: "missing-args",
message: "Required arguments missing",
severity: .error
)
)
)
return []
}
// Implementation...
return []
}
}
// Structure for diagnostic messages
struct MacroDiagnosticMessage: DiagnosticMessage {
let id: String
let message: String
let severity: DiagnosticSeverity
var diagnosticID: MessageID {
MessageID(domain: "MyMacros", id: id)
}
}Sinh ma de doc
// Avoid: hard-to-read generated code
let badCode: DeclSyntax = "public init(a:Int,b:String,c:Bool){self.a=a;self.b=b;self.c=c}"
// Preferred: properly formatted generated code
let goodCode: DeclSyntax = """
public init(
a: Int,
b: String,
c: Bool
) {
self.a = a
self.b = b
self.c = c
}
"""Ma duoc sinh nen de doc nhu ma viet tay vi lap trinh vien se kiem tra qua "Expand Macro".
Nguon tham khao
- SE-0415: Function Body Macros, trien khai trong Swift 6.0
- swift-syntax releases, phien ban 600.0.0+ cho Swift 6
- Swift.org Blog, ghi chu phat hanh Swift 6.3
Kha nang cua Swift Macros trong thuc te
Swift Macros la cong cu manh me de loai bo boilerplate ma van giu duoc an toan kieu tinh. Cong nghe nay cho phep:
- Hai nhom macro: freestanding (
#) va attached (@) - Sau vai tro attached trong Swift 6: peer, accessor, member, memberAttribute, extension, va vai tro body moi
- Trien khai bang swift-syntax 600.0.0+ va thao tac AST
- Bat buoc kiem thu voi
SwiftSyntaxMacrosTestSupport, hien ho tro Swift Testing - Yeu cau goi rieng cho phan trien khai
- Go loi qua "Expand Macro" trong Xcode
- Thong bao loi ro rang la yeu to thiet yeu cho trai nghiem lap trinh vien
Swift Macros dac biet huu ich de sinh cac conformance (Equatable, Codable), tao property wrapper nang cao, tong hop trien khai RPC tu chu ky, va hien dai hoa cac API dua tren callback sang async/await.
Bắt đầu luyện tập!
Kiểm tra kiến thức với mô phỏng phỏng vấn và bài kiểm tra kỹ thuật.
Bạn có tìm ra lỗi trong iOS không?
Một đoạn mã thật, một lỗi ẩn, mỗi ngày một lượt. Không cần tài khoản để thử.

Viết bởi
Anthony Fillion-MailletNgười sáng lập SharpSkill
Lập trình viên fullstack hơn 10 năm. Anh điều hành SharpSkill và chịu trách nhiệm về mọi nội dung đăng tại đây.
Cập nhật ngày 23 tháng 8, 2026
Thẻ
Chia sẻ
Bài viết liên quan

Việc làm lập trình viên iOS 2026: Nguồn tuyển dụng, mức lương, cách chuẩn bị phỏng vấn
Hướng dẫn toàn diện tìm việc lập trình viên iOS năm 2026. Khám phá nguồn tuyển dụng, dữ liệu lương thực tế, và chiến lược chuẩn bị phỏng vấn kỹ thuật.

Combine vs async/await trong Swift: Mẫu Hình Di Cư Tiến Bộ
Hướng dẫn đầy đủ về di cư từ Combine sang async/await trong Swift: chiến lược tiến bộ, mẫu hình bắc cầu và sự cùng tồn tại của các mô hình trong codebase iOS.

Câu hỏi phỏng vấn về khả năng tiếp cận iOS năm 2026: VoiceOver và Dynamic Type
Chuẩn bị phỏng vấn iOS với những câu hỏi then chốt về khả năng tiếp cận: VoiceOver, Dynamic Type, các trait ngữ nghĩa và kiểm thử.