mirror of
https://github.com/harivansh-afk/claude-code-vertical.git
synced 2026-04-18 13:04:01 +00:00
skills
This commit is contained in:
parent
087b195b4c
commit
ae037f7bec
24 changed files with 15692 additions and 0 deletions
375
skill-index/skills/axiom-networking/LEGACY-IOS12-25.md
Normal file
375
skill-index/skills/axiom-networking/LEGACY-IOS12-25.md
Normal file
|
|
@ -0,0 +1,375 @@
|
|||
# Legacy iOS 12-25 NWConnection Patterns
|
||||
|
||||
These patterns use NWConnection with completion handlers for apps supporting iOS 12-25. If your app targets iOS 26+, use NetworkConnection with async/await instead (see main SKILL.md).
|
||||
|
||||
---
|
||||
|
||||
## Pattern 2a: NWConnection with TLS (iOS 12-25)
|
||||
|
||||
**Use when** Supporting iOS 12-25, need TLS encryption, can't use async/await yet
|
||||
|
||||
**Time cost** 10-15 minutes
|
||||
|
||||
#### ✅ GOOD: NWConnection with Completion Handlers
|
||||
|
||||
```swift
|
||||
import Network
|
||||
|
||||
// Create connection with TLS
|
||||
let connection = NWConnection(
|
||||
host: NWEndpoint.Host("mail.example.com"),
|
||||
port: NWEndpoint.Port(integerLiteral: 993),
|
||||
using: .tls // TCP inferred
|
||||
)
|
||||
|
||||
// Handle connection state changes
|
||||
connection.stateUpdateHandler = { [weak self] state in
|
||||
switch state {
|
||||
case .ready:
|
||||
print("Connection established")
|
||||
self?.sendInitialData()
|
||||
case .waiting(let error):
|
||||
print("Waiting for network: \(error)")
|
||||
// Show "Waiting..." UI, don't fail immediately
|
||||
case .failed(let error):
|
||||
print("Connection failed: \(error)")
|
||||
case .cancelled:
|
||||
print("Connection cancelled")
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Start connection
|
||||
connection.start(queue: .main)
|
||||
|
||||
// Send data with pacing
|
||||
func sendData() {
|
||||
let data = Data("Hello, world!".utf8)
|
||||
connection.send(content: data, completion: .contentProcessed { [weak self] error in
|
||||
if let error = error {
|
||||
print("Send error: \(error)")
|
||||
return
|
||||
}
|
||||
// contentProcessed callback = network stack consumed data
|
||||
// This is when you should send next chunk (pacing)
|
||||
self?.sendNextChunk()
|
||||
})
|
||||
}
|
||||
|
||||
// Receive exact byte count
|
||||
func receiveData() {
|
||||
connection.receive(minimumIncompleteLength: 10, maximumLength: 10) { [weak self] (data, context, isComplete, error) in
|
||||
if let error = error {
|
||||
print("Receive error: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
if let data = data {
|
||||
print("Received \(data.count) bytes")
|
||||
// Process data...
|
||||
self?.receiveData() // Continue receiving
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Key differences from NetworkConnection
|
||||
- Must use `[weak self]` in all completion handlers to prevent retain cycles
|
||||
- stateUpdateHandler receives state, not async sequence
|
||||
- send/receive use completion callbacks, not async/await
|
||||
|
||||
#### When to use
|
||||
- Supporting iOS 12-15 (70% of devices as of 2024)
|
||||
- Codebases not yet using async/await
|
||||
- Libraries needing backward compatibility
|
||||
|
||||
#### Migration to NetworkConnection (iOS 26+)
|
||||
- stateUpdateHandler → connection.states async sequence
|
||||
- Completion handlers → try await calls
|
||||
- [weak self] → No longer needed (async/await handles cancellation)
|
||||
|
||||
---
|
||||
|
||||
## Pattern 2b: NWConnection UDP Batch (iOS 12-25)
|
||||
|
||||
**Use when** Supporting iOS 12-25, sending multiple UDP datagrams efficiently, need ~30% CPU reduction
|
||||
|
||||
**Time cost** 10-15 minutes
|
||||
|
||||
**Background** Traditional UDP sockets send one datagram per syscall. If you're sending 100 small packets, that's 100 context switches. Batching reduces this to ~1 syscall.
|
||||
|
||||
#### ❌ BAD: Individual UDP Sends (High CPU)
|
||||
```swift
|
||||
// WRONG — 100 context switches for 100 packets
|
||||
for frame in videoFrames {
|
||||
sendto(socket, frame.bytes, frame.count, 0, &addr, addrlen)
|
||||
// Each send = context switch to kernel
|
||||
}
|
||||
```
|
||||
|
||||
#### ✅ GOOD: Batched UDP Sends (30% Lower CPU)
|
||||
|
||||
```swift
|
||||
import Network
|
||||
|
||||
// UDP connection
|
||||
let connection = NWConnection(
|
||||
host: NWEndpoint.Host("stream-server.example.com"),
|
||||
port: NWEndpoint.Port(integerLiteral: 9000),
|
||||
using: .udp
|
||||
)
|
||||
|
||||
connection.stateUpdateHandler = { state in
|
||||
if case .ready = state {
|
||||
print("Ready to send UDP")
|
||||
}
|
||||
}
|
||||
|
||||
connection.start(queue: .main)
|
||||
|
||||
// Batch sending for efficiency
|
||||
func sendVideoFrames(_ frames: [Data]) {
|
||||
connection.batch {
|
||||
for frame in frames {
|
||||
connection.send(content: frame, completion: .contentProcessed { error in
|
||||
if let error = error {
|
||||
print("Send error: \(error)")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
// All sends batched into ~1 syscall
|
||||
// 30% lower CPU usage vs individual sends
|
||||
}
|
||||
|
||||
// Receive UDP datagrams
|
||||
func receiveFrames() {
|
||||
connection.receive(minimumIncompleteLength: 1, maximumLength: 65536) { [weak self] (data, context, isComplete, error) in
|
||||
if let error = error {
|
||||
print("Receive error: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
if let data = data {
|
||||
// Process video frame
|
||||
self?.displayFrame(data)
|
||||
self?.receiveFrames() // Continue receiving
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Performance characteristics
|
||||
- **Without batch** 100 datagrams = 100 syscalls = 100 context switches
|
||||
- **With batch** 100 datagrams = ~1 syscall = 1 context switch
|
||||
- **Result** ~30% lower CPU usage (measured with Instruments)
|
||||
|
||||
#### When to use
|
||||
- Real-time video/audio streaming
|
||||
- Gaming with frequent updates (player position)
|
||||
- High-frequency sensor data (IoT)
|
||||
|
||||
**WWDC 2018 demo** Live video streaming showed 30% lower CPU on receiver with user-space networking + batching
|
||||
|
||||
---
|
||||
|
||||
## Pattern 2c: NWListener (iOS 12-25)
|
||||
|
||||
**Use when** Need to accept incoming connections, building servers or peer-to-peer apps, supporting iOS 12-25
|
||||
|
||||
**Time cost** 20-25 minutes
|
||||
|
||||
#### ❌ BAD: Manual Socket Listening
|
||||
```swift
|
||||
// WRONG — Manual socket management
|
||||
let sock = socket(AF_INET, SOCK_STREAM, 0)
|
||||
bind(sock, &addr, addrlen)
|
||||
listen(sock, 5)
|
||||
while true {
|
||||
let client = accept(sock, nil, nil) // Blocks thread
|
||||
// Handle client...
|
||||
}
|
||||
```
|
||||
|
||||
#### ✅ GOOD: NWListener with Automatic Connection Handling
|
||||
|
||||
```swift
|
||||
import Network
|
||||
|
||||
// Create listener with default parameters
|
||||
let listener = try NWListener(using: .tcp, on: 1029)
|
||||
|
||||
// Advertise Bonjour service
|
||||
listener.service = NWListener.Service(name: "MyApp", type: "_myservice._tcp")
|
||||
|
||||
// Handle service registration updates
|
||||
listener.serviceRegistrationUpdateHandler = { update in
|
||||
switch update {
|
||||
case .add(let endpoint):
|
||||
if case .service(let name, let type, let domain, _) = endpoint {
|
||||
print("Advertising as: \(name).\(type)\(domain)")
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Handle incoming connections
|
||||
listener.newConnectionHandler = { [weak self] newConnection in
|
||||
print("New connection from: \(newConnection.endpoint)")
|
||||
|
||||
// Configure connection
|
||||
newConnection.stateUpdateHandler = { state in
|
||||
switch state {
|
||||
case .ready:
|
||||
print("Client connected")
|
||||
self?.handleClient(newConnection)
|
||||
case .failed(let error):
|
||||
print("Client connection failed: \(error)")
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Start handling this connection
|
||||
newConnection.start(queue: .main)
|
||||
}
|
||||
|
||||
// Handle listener state
|
||||
listener.stateUpdateHandler = { state in
|
||||
switch state {
|
||||
case .ready:
|
||||
print("Listener ready on port \(listener.port ?? 0)")
|
||||
case .failed(let error):
|
||||
print("Listener failed: \(error)")
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Start listening
|
||||
listener.start(queue: .main)
|
||||
|
||||
// Handle client data
|
||||
func handleClient(_ connection: NWConnection) {
|
||||
connection.receive(minimumIncompleteLength: 1, maximumLength: 65536) { [weak self] (data, context, isComplete, error) in
|
||||
if let error = error {
|
||||
print("Receive error: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
if let data = data {
|
||||
print("Received \(data.count) bytes")
|
||||
|
||||
// Echo back
|
||||
connection.send(content: data, completion: .contentProcessed { error in
|
||||
if let error = error {
|
||||
print("Send error: \(error)")
|
||||
}
|
||||
})
|
||||
|
||||
self?.handleClient(connection) // Continue receiving
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### When to use
|
||||
- Peer-to-peer apps (file sharing, messaging)
|
||||
- Local network services
|
||||
- Development/testing servers
|
||||
|
||||
#### Bonjour advertising
|
||||
- Automatic service discovery on local network
|
||||
- No hardcoded IPs needed
|
||||
- Works with NWBrowser for discovery
|
||||
|
||||
#### Security considerations
|
||||
- Use TLS parameters for encryption: `NWListener(using: .tls, on: port)`
|
||||
- Validate client connections before processing data
|
||||
- Set connection limits to prevent DoS
|
||||
|
||||
---
|
||||
|
||||
## Pattern 2d: Network Discovery (iOS 12-25)
|
||||
|
||||
**Use when** Discovering services on local network (Bonjour), building peer-to-peer apps, supporting iOS 12-25
|
||||
|
||||
**Time cost** 25-30 minutes
|
||||
|
||||
#### ❌ BAD: Hardcoded IP Addresses
|
||||
```swift
|
||||
// WRONG — Brittle, requires manual configuration
|
||||
let connection = NWConnection(host: "192.168.1.100", port: 9000, using: .tcp)
|
||||
// What if IP changes? What if multiple devices?
|
||||
```
|
||||
|
||||
#### ✅ GOOD: NWBrowser for Service Discovery
|
||||
|
||||
```swift
|
||||
import Network
|
||||
|
||||
// Browse for services on local network
|
||||
let browser = NWBrowser(for: .bonjour(type: "_myservice._tcp", domain: nil), using: .tcp)
|
||||
|
||||
// Handle discovered services
|
||||
browser.browseResultsChangedHandler = { results, changes in
|
||||
for result in results {
|
||||
switch result.endpoint {
|
||||
case .service(let name, let type, let domain, _):
|
||||
print("Found service: \(name).\(type)\(domain)")
|
||||
// Connect to this service
|
||||
self.connectToService(result.endpoint)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle browser state
|
||||
browser.stateUpdateHandler = { state in
|
||||
switch state {
|
||||
case .ready:
|
||||
print("Browser ready")
|
||||
case .failed(let error):
|
||||
print("Browser failed: \(error)")
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Start browsing
|
||||
browser.start(queue: .main)
|
||||
|
||||
// Connect to discovered service
|
||||
func connectToService(_ endpoint: NWEndpoint) {
|
||||
let connection = NWConnection(to: endpoint, using: .tcp)
|
||||
|
||||
connection.stateUpdateHandler = { state in
|
||||
if case .ready = state {
|
||||
print("Connected to service")
|
||||
}
|
||||
}
|
||||
|
||||
connection.start(queue: .main)
|
||||
}
|
||||
```
|
||||
|
||||
#### When to use
|
||||
- Peer-to-peer discovery (AirDrop-like features)
|
||||
- Local network printers, media servers
|
||||
- Development/testing (find test servers automatically)
|
||||
|
||||
#### Performance characteristics
|
||||
- mDNS-based (multicast DNS, no central server)
|
||||
- Near-instant discovery on same subnet
|
||||
- Automatic updates when services appear/disappear
|
||||
|
||||
#### iOS 26+ alternative
|
||||
- Use NetworkBrowser with Wi-Fi Aware for peer-to-peer without infrastructure
|
||||
- See Pattern 1d in network-framework-ref skill
|
||||
|
||||
---
|
||||
|
||||
Return to [main networking skill](SKILL.md).
|
||||
Loading…
Add table
Add a link
Reference in a new issue