Итак, вы только что прочитали две предыдущие статьи о Naked Networking, если вы их пропустили, вот несколько ссылок.

Голая сеть с SwiftUI
Больше голой сети, больше SwiftUI

Тогда план этой статьи. В первом я описал, как настроить прослушиватель для пакетов UDP, во втором мы настроили передатчик для отправки пакетов UDP, оба интерфейса связаны с использованием новой среды SwiftUI. На этот раз мы собираемся модифицировать нашу программу для создания игры. Я имею в виду игру в пинг-понг с использованием двух устройств iOS.

Сеть

Сначала мы начнем с изменений в сетевой структуре, которых почти нет. Нам нужно добавить еще один метод в наш класс.

func stopListening() {
self.listening?.cancel()
}

Это простая процедура для отключения интерфейса прослушивания по требованию. В нашей игре; по умолчанию он будет прослушивать порт 1984; давая возможность закрыть этот демон и запустить один, прослушивающий 4819. Идея состоит в том, что idevice A будет слушать 1984, а idevice B — 4819. Они будут отправлять пакеты на свои одноранговые порты. Итак, idevice 1984 отправит эхо-запрос на 4819. А idevice 4819 отправит эхо-запрос на 1984.

SwiftUI

Большинство изменений в файле ContentView.swift. Во-первых, нам нужно определить новый класс, который мы свяжем с переключателем, который мы добавим, чтобы выбрать, на чьей вы стороне: 1984 или 4819. Мы также собираемся дать нашим игрокам имена. Мы будем называть 1984 «инь», а 4819 — «ян».

struct ToggleModel {
var state: Bool = false {
willSet {
if state {
communication.stopListening()
let port2U = NWEndpoint.Port.init(integerLiteral: 1984)
communication.listenUDP(port: port2U)
player = "ying"
globalVariable.score = "pong"
print("1984")
} else {
communication.stopListening()
let port2U = NWEndpoint.Port.init(integerLiteral: 4891)
communication.listenUDP(port: port2U)
player = "yang"
globalVariable.score = "ping"
print("4891")
}
}
}
}

Что делает этот код. Это простая структура, которая представляет собой не что иное, как логическое значение, которым будет управлять переключатель iOS. Если это правда, то вы слушаете 1984 год, передаете 4891. Если это неверно, то вы слушаете 4891 и передаете 1984 год. Мы также устанавливаем соответствующую метку на переключателе внутри него. Если верно, вы должны быть «ян», если неверно, вы, очевидно, «инь». Мы устанавливаем метку счета для принудительного обновления, на самом деле это хак.

Далее нам нужно изменить код в теле представления. Вверху, перед Text("\(globalVariable.score)"), мы добавляем переключатель и ссылаемся на нашу новую структуру, которую мы только что определили. Код фрейма просто перемещает переключатель в центр экрана.

Toggle("", isOn: $model.state).frame(width: 128, height: 64, alignment: .center)

Блок .onAppear остался без изменений, но нам нужно переписать код кнопки. Я показываю весь шебанг для полноты картины.

Button(action: {
if self.model.state {
makeConnect(port: "1984", message: "ping")
self.globalVariable.score = "ping"
} else {
makeConnect(port: "4891", message: "pong")
self.globalVariable.score = "pong"
}
}) {
Text("whack")
}

Что мы сделали. Мы добавили простой тест, который проверяет значение переключателя и при необходимости отправляет соответствующий пинг или понг. Когда мы отправляем его, мы также меняем локальную метку, чтобы отразить тот факт, что мы только что пинговали.

Внесите изменения и вперед. Если вы ян и нажимаете удар, метка инь меняется на пинг. Если ваш инь и вы нажмете ударить, метка на ян изменится на понг.

Бон, но подождите, прежде чем мы закончим, мы использовали технику, которая, как я намекнул, была скорее хаком, чем реальным решением. Давайте вернемся к нему и сделаем последнюю настройку, чтобы сделать это приложение немного лучше.

Вернитесь к файлу Connect.swift и добавьте строки, которые вы видите здесь, выделенные полужирным курсивом. Вы используете другой новый фреймворк под названием Combine. В указанной структуре мы определяем протокол сообщений, который не будет содержать данных и никогда не будет сообщать об ошибке, поскольку название предполагает не что иное, как pingProtocol.

import Combine
let pingPublisher = PassthroughSubject<Void, Never>()
...
DispatchQueue.main.async {
globalVariable.score = backToString
pingPublisher.send()
}

Мы пингуем наш интерфейс, когда получаем данные через сетевой интерфейс.

Вернувшись в ContentView.swift, нам нужно добавить строки, выделенные полужирным курсивом. Что мы делаем? Переменная обновления просто обновляет дисплей, когда он изменяется, а флаг отключения не позволяет вам нажимать удар.

@State var model = ToggleModel()
@State var refresh = false
@State var disable = false
...
.onAppear {
let port2U = NWEndpoint.Port.init(integerLiteral: 1984)
communication.listenUDP(port: port2U)
}.onReceive(pingPublisher) { (_) in
self.disable = false
}
...
Button(action: {
if self.model.state {
makeConnect(port: "1984", message: "ping")
self.disable = true
self.refresh = !self.refresh
} else {
makeConnect(port: "4891", message: "pong")
self.disable = true
self.refresh = !self.refresh
}
}) {
Text("whack")
.disabled(disable)
}

Идея довольно проста. После того, как вы вернете пинг, вам нужно подождать, пока он вернется к вам, прежде чем вы сможете снова его щелкнуть. Вам нужно дождаться своей очереди.

Вам это нравится? давайте нажмем, чтобы прочитать следующую статью о голых сетях здесь.