Just adding
.localto the host name solved the problem.
No it doesn’t. The Bonjour service name and the local DNS name do not need to be related and, even when they are, it’s common for them to be significantly different. For some fun examples of this, see this post.
The only way to get the DNS name of a service is to resolve it.
But it still freezing my app just after service found
Hmmm, I can’t spot the error. Rather than spend time debugging that I created a small test program that illustrates one way to do this. If you paste the code below into a new command-line tool project, it should be able to resolve any service you give it.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
import Foundation
final class BonjourResolver: NSObject, NetServiceDelegate {
typealias CompletionHandler = (Result<(String, Int), Error>) -> Void
@discardableResult
static func resolve(service: NetService, completionHandler: @escaping CompletionHandler) -> BonjourResolver {
precondition(Thread.isMainThread)
let resolver = BonjourResolver(service: service, completionHandler: completionHandler)
resolver.start()
return resolver
}
private init(service: NetService, completionHandler: @escaping CompletionHandler) {
// We want our own copy of the service because we’re going to set a
// delegate on it but `NetService` does not conform to `NSCopying` so
// instead we create a copy by copying each property.
let copy = NetService(domain: service.domain, type: service.type, name: service.name)
self.service = copy
self.completionHandler = completionHandler
}
deinit {
// If these fire the last reference to us was released while the resolve
// was still in flight. That should never happen because we retain
// ourselves on `start`.
assert(self.service == nil)
assert(self.completionHandler == nil)
assert(self.selfRetain == nil)
}
private var service: NetService? = nil
private var completionHandler: (CompletionHandler)? = nil
private var selfRetain: BonjourResolver? = nil
private func start() {
precondition(Thread.isMainThread)
guard let service = self.service else { fatalError() }
service.delegate = self
service.resolve(withTimeout: 5.0)
// Form a temporary retain loop to prevent us from being deinitialised
// while the resolve is in flight. We break this loop in `stop(with:)`.
selfRetain = self
}
func stop() {
self.stop(with: .failure(CocoaError(.userCancelled)))
}
private func stop(with result: Result<(String, Int), Error>) {
precondition(Thread.isMainThread)
self.service?.delegate = nil
self.service?.stop()
self.service = nil
let completionHandler = self.completionHandler
self.completionHandler = nil
completionHandler?(result)
selfRetain = nil
}
func netServiceDidResolveAddress(_ sender: NetService) {
let hostName = sender.hostName!
let port = sender.port
self.stop(with: .success((hostName, port)))
}
func netService(_ sender: NetService, didNotResolve errorDict: [String: NSNumber]) {
let code = (errorDict[NetService.errorCode]?.intValue)
.flatMap { NetService.ErrorCode.init(rawValue: $0) }
?? .unknownError
let error = NSError(domain: NetService.errorDomain, code: code.rawValue, userInfo: nil)
self.stop(with: .failure(error))
}
}
func main() {
let service = NetService(domain: "local.", type: "_ssh._tcp", name: "Fluffy")
print("will resolve, service: \(service)")
BonjourResolver.resolve(service: service) { result in
switch result {
case .success(let hostName):
print("did resolve, host: \(hostName)")
exit(EXIT_SUCCESS)
case .failure(let error):
print("did not resolve, error: \(error)")
exit(EXIT_FAILURE)
}
}
RunLoop.current.run()
}
main()