Ee632636401a4d6cfb1303f4a96afb9c
SwiftUI 网络编程大全之去中心化对等网络区块链应用源码

实战需求

SwiftUI 网络编程大全之去中心化对等网络区块链应用源码

本文价值与收获

看完本文后,您将能够作出下面的界面

SwiftUI 网络编程大全之去中心化对等网络区块链应用源码

SwiftUI 网络编程大全之去中心化对等网络区块链应用源码

看完本文您将掌握的技能

  • 使用Bonjour、TCP和TLS在设备之间建立安全连接。
  • 定义了一个简单的自定义协议
  • 用于在任何两个用户之间发送消息
  • 去中心点对点交易协商
  • 多终端支持iOS、macOS

实战代码

1、 主视图

import SwiftUI

struct RootView: View {
    @StateObject var manager: ExchangeManager = ExchangeManager()
    @AppStorage("Bitfinex_Demo_Name") var username: String = ""

    var body: some View {
        NavigationView {
            if !username.isEmptyOrWhitespace {
                DashboardView()
                    .environmentObject(manager)
            } else {
                ProfileSetupView()
            }
        }.onAppear(perform: {
            Preferences().initUser()
            if sharedBrowser == nil {
                sharedBrowser = PeerBrowser(delegate: manager)
            }
        })
    }
}

2、管理视图
```
import SwiftUI
import Network
import SwiftyJSON

struct DashboardView: View {
@EnvironmentObject var manager: ExchangeManager
@State private var price: String = ""
@State private var amount: String = ""
@State private var selectedListing: Listing?
@State private var negotiating: Bool = false

var postDisabled: Bool {
    return price.isEmptyOrWhitespace || amount.isEmptyOrWhitespace
}


var body: some View {
    VStack {
        List {
            Section(header: Text("Exchange Sell")) {
                GroupBox {
                    HStack {
                        VStack(alignment: .leading) {
                            Text("Price USD")
                            TextField("Enter price", text: $price)
                                .padding(8)
                                .keyboardType(.numberPad)
                                .background(RoundedRectangle(cornerRadius: 12).stroke().foregroundColor(.secondary))
                        }

                        Divider()

                        VStack(alignment: .leading) {
                            Text("Amount BTC")
                            TextField("Enter amount", text: $amount)
                                .padding(8)
                                .keyboardType(.numberPad)
                                .background(RoundedRectangle(cornerRadius: 12).stroke().foregroundColor(.secondary))
                        }
                    }

                    Divider()
                        .padding(.vertical, 10)

                    HStack {
                        Button(action: { clearFields() }, label: {
                            VStack {
                                Text("Clear".uppercased())
                                    .padding(8)
                            }
                            .padding(.horizontal)
                            .background(RoundedRectangle(cornerRadius: 20).stroke())
                        })

                        Button(action: { postListing() }, label: {
                            VStack {
                                Text("Post".uppercased())
                                    .padding(8)
                                    .foregroundColor(.white)
                            }
                            .padding(.horizontal)
                            .background(RoundedRectangle(cornerRadius: 20))
                        })
                        .disabled(postDisabled)
                    }
                }
            }

            Section(header: Text("Exchange Buy")) {
                ScrollView {
                    VStack {
                        if manager.results.isEmpty {
                            HStack {
                                Spacer()
                                Text("No listings yet...")
                                    .italic()
                                    .fontWeight(.thin)
                                Spacer()
                            }
                            .padding()
                        } else {
                            ForEach(manager.results, id: \.self) { result in
                                if case let NWEndpoint.service(name: name, type: _, domain: _, interface: _) = result.endpoint, let listing = Listing(json: JSON(parseJSON: name)) {
                                    Button(action: { makeOffer(result: result, listing: listing) }, label: {
                                        VStack {
                                            HStack(spacing: 10) {
                                                Image("bitfinex-avatar")
                                                    .resizable()
                                                    .frame(width: 50, height: 50, alignment: .center)
                                                    .clipShape(Circle())
                                                VStack(alignment: .leading) {
                                                    Text(listing.name)
                                                        .font(.body)
                                                        .fontWeight(.semibold)
                                                    HStack {
                                                        Text("Price USD: \(listing.price)")
                                                            .font(.callout)
                                                            .fontWeight(.light)
                                                        Text("|")
                                                        Text("Amount BTC: \(listing.amount)")
                                                            .font(.callout)
                                                            .fontWeight(.light)
                                                    }
                                                }
                                                Spacer()
                                            }
                                            .frame(maxWidth: .infinity)
                                        }
                                    })
                                }
                            }
                        }
                    }
                }
            }
        }
        .listStyle(GroupedListStyle())

    }
    .onReceive(manager.$connectionStatus, perform: { value in
        if !negotiating, value == 1, manager.myListing != nil {
            selectedListing = manager.myListing
            negotiating = true
        }
    })
    .onChange(of: negotiating, perform: { value in
        if !negotiating, let connection = sharedConnection {
            if connection.initiatedConnection {
                connection.cancel()
                sharedConnection = nil
            }
        }
    })
    .sheet(isPresented: $negotiating, content: {
        if let listing = selectedListing {
            NegotiationView(isPresented: $negotiating, listing: listing)
                .environmentObject(manager)
        }
    })
    .navigationBarTitle("Trading", displayMode: .inline)
    .navigationBarItems(leading:
                            HStack {
                                Text(Preferences().userName.prefix(1).uppercased())
                                .font(.title2)
                            }
                            .padding(8)
                            .background(Circle().stroke()))
}

func makeOffer(result: NWBrowser.Result, listing: Listing) {
    sharedConnection = PeerConnection(endpoint: result.endpoint,
        interface: result.interfaces.first,
        passcode: "1155",
        delegate: manager)

    selectedListing = listing
    negotiating = true
}

func postListing() {
    let listingJsonString = createListing().toJSON().description
    if let listener = sharedListener {
        // If your app is already listening, just update listing.
        listener.resetName(listingJsonString)
    } else {
        // If your app is not yet listening, start a new listener.
        sharedListener = PeerListener(name: listingJsonString, passcode: "1155", delegate: manager)
    }
    clearFields()
}

func createListing() -> Listing {
    let prefs = Preferences()
    let listing = Listing()
    listing.amount = amount
    listing.price = price
    listing.name = prefs.userName
    return listing
}

func clearFields() {
    self.amount = ""
    self.price = ""
}

}

struct DashboardView_Previews: PreviewProvider {
static var previews: some View {
DashboardView()
}
}

struct PlainGroupBoxStyle: GroupBoxStyle {
func makeBody(configuration: Configuration) -> some View {
VStack(alignment: .center) {
configuration.label

top Created with Sketch.