Bonjour Service Browser with Swift does not fetch serviceinfo - swift

The service I want to connect to is published via Bonjour.
I can find all the info with the Bonjour Browser, however if I try to gather the data programmatically, the only value I get, is the name of the service.
The NetService delegate is set and the function netServiceWillPublish is called.
The functions DidNotPublish or DidPublish are not executed.
The function netServiceBrowser gets all published netServices, but all properties are set to the default value of the datatype.
import UIKit
class BMNSDelegate : NSObject, NetServiceDelegate {
func netServiceWillPublish(_ sender: NetService) {
print("netServiceWillPublish:\(sender)"); //This method is called
}
func netService(_ sender: NetService, didNotPublish errorDict: [String : NSNumber]){
print("didNotPublish:\(sender)");
}
func netServiceDidPublish(_ sender: NetService) {
print("netServiceDidPublish:\(sender)");
}
func netServiceWillResolve(_ sender: NetService) {
print("netServiceWillResolve:\(sender)");
}
func netService(_ sender: NetService, didNotResolve errorDict: [String : NSNumber]) {
print("netServiceDidNotResolve:\(sender)");
}
func netServiceDidResolveAddress(_ sender: NetService) {
print("netServiceDidResolve:\(sender)");
}
func netService(_ sender: NetService, didUpdateTXTRecord data: Data) {
print("netServiceDidUpdateTXTRecordData:\(sender)");
}
func netServiceDidStop(_ sender: NetService) {
print("netServiceDidStopService:\(sender)");
}
func netService(_ sender: NetService,
didAcceptConnectionWith inputStream: InputStream,
outputStream stream: OutputStream) {
print("netServiceDidAcceptConnection:\(sender)");
}
}
class BMBrowserDelegate : NSObject, NetServiceBrowserDelegate, NetServiceDelegate {
func netServiceBrowser(_ netServiceBrowser: NetServiceBrowser,
didFind netService: NetService,
moreComing moreServicesComing: Bool) {
let nsnsdel = BMNSDelegate()
netService.delegate = nsnsdel
netService.resolve(withTimeout: 1)
print(netService.domain) // local.
print(netService.name) // This property is correct
print(netService.type) // _http._tcp.
print(netService.addresses) // Optional([])
print(netService.hostName) // nil
print(netService.port) // -1
print(moreServicesComing) //false
}
}
let SERVICE_TYPE = "_http._tcp."
let BM_DOMAIN = "local."
let browser = NetServiceBrowser()
let nsbdel = BMBrowserDelegate()
browser.delegate = nsbdel
browser.searchForServices(ofType: SERVICE_TYPE, inDomain: BM_DOMAIN)
RunLoop.current.run()

The error is that the services which are found in the ServiceBrowserDelegate function are not saved anywhere and therefore are discarded at the end of the function.
I found a working example here:
https://github.com/mattneub/Programming-iOS-Book-Examples/blob/61f0c753a080040e4a74b912e6c18dd97fe8bcaa/bk2ch24p853bonjour/ch37p1101bonjour/ViewController.swift
class ViewController: UIViewController, NetServiceBrowserDelegate, NetServiceDelegate {
var nsb : NetServiceBrowser!
var services = [NetService]()
#IBAction func doButton (_ sender: Any!) {
print("listening for services...")
self.services.removeAll()
self.nsb = NetServiceBrowser()
self.nsb.delegate = self
self.nsb.searchForServices(ofType:"_daap._tcp", inDomain: "")
}
func updateInterface () {
for service in self.services {
if service.port == -1 {
print("service \(service.name) of type \(service.type)" +
" not yet resolved")
service.delegate = self
service.resolve(withTimeout:10)
} else {
print("service \(service.name) of type \(service.type)," +
"port \(service.port), addresses \(service.addresses)")
}
}
}
func netServiceDidResolveAddress(_ sender: NetService) {
self.updateInterface()
}
func netServiceBrowser(_ aNetServiceBrowser: NetServiceBrowser, didFind aNetService: NetService, moreComing: Bool) {
print("adding a service")
self.services.append(aNetService)
if !moreComing {
self.updateInterface()
}
}
func netServiceBrowser(_ aNetServiceBrowser: NetServiceBrowser, didRemove aNetService: NetService, moreComing: Bool) {
if let ix = self.services.index(of:aNetService) {
self.services.remove(at:ix)
print("removing a service")
if !moreComing {
self.updateInterface()
}
}
}
}

Related

What is a good way to handle async requests in ReSwift/Redux

To make an asynchronous request a middleware is used in this case, it returns an error after a fixed amount of time.
The app state is properly updated the subscriber view controller presents the error.
On the next instance however this subscriber view controller is presented, it finds the error in the state - which is actually the error from the previous request and displays the error message before even the request is fired.
How to go about handling this case in ReSwift/Redux?
Store
let store = Store(
reducer: appReducer,
state: AppState(),
middleware: [requestMiddleware]
)
State
struct AppState: StateType {
var isRequestInProgress = false
var result: Result<Bool, NSError>?
}
Actions
struct RequestAction: Action {}
struct ReceiveAction: Action {}
struct ErrorAction: Action {
let error: NSError
}
Middleware
let requestMiddleware: Middleware<Any> = { dispatch, getState in
return { next in
return { action in
switch action {
case is RequestAction:
DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
store.dispatch(ErrorAction(error: NSError(domain: "", code: -1, userInfo: nil)))
})
default:
break
}
return next(action)
}
}
}
Reducer
func appReducer(action: Action, state: AppState?) -> AppState {
var state = state ?? AppState()
switch action {
case is RequestAction:
state.isRequestInProgress = true
case let action as ErrorAction:
state.isRequestInProgress = false
state.result = .failure(action.error)
default: break
}
return state
}
The app
class ViewController: UIViewController {
#IBAction func presentControllerB(_ sender: Any) {
guard let viewController = storyboard?.instantiateViewController(withIdentifier: "ViewControllerB") else {
return
}
present(viewController, animated: true)
}
}
class ViewControllerB: UIViewController, StoreSubscriber {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
store.subscribe(self)
}
override func viewWillDisappear(_ animated: Bool) {
store.unsubscribe(self)
super.viewWillDisappear(animated)
}
func newState(state: AppState) {
showActivity(state.isRequestInProgress)
switch state.result {
case .none:
break
case .some(.success(_)):
break
case .some(.failure(let error)):
presentError(error)
dismiss(animated: true)
}
}
#IBAction func request(_ sender: Any) {
store.dispatch(RequestAction())
}
private func showActivity(_ show: Bool) {}
private func presentError(_ error: Error) {
print("Error")
}
}

AVCaptureMetadataObjectDelegate not receiving callback

I am making QR scanner. My code is working when all of it written in one place inside ViewController but when I modularised it then I am not getting callback inside AVCaptureMetadataOutputObjectsDelegate.
import Foundation
import UIKit
import AVFoundation
class CameraSource : NSObject {
private var session : AVCaptureSession?
private var inputDevice : AVCaptureDeviceInput?
private var videoPreviewLayer : AVCaptureVideoPreviewLayer?
private var captureMetadataOutput : AVCaptureMetadataOutput?
func setCaptureMetadataOutput() {
self.captureMetadataOutput = nil
self.captureMetadataOutput = AVCaptureMetadataOutput()
}
func getCaptureMetadataOutput() -> AVCaptureMetadataOutput? {
return self.captureMetadataOutput
}
func setInputDevice(inputDevice : AVCaptureDeviceInput?) {
self.inputDevice = inputDevice
}
func getInputDevice() -> AVCaptureDeviceInput? {
return self.inputDevice
}
func setSession(session : AVCaptureSession?) {
self.session = session
}
func getSession() -> AVCaptureSession? {
return self.session
}
func setMetadataObjects(metaObjects : [AVMetadataObject.ObjectType], delegate : AVCaptureMetadataOutputObjectsDelegate) {
assert(self.captureMetadataOutput != nil)
self.captureMetadataOutput!.setMetadataObjectsDelegate(delegate, queue: DispatchQueue.main)
self.captureMetadataOutput!.metadataObjectTypes = metaObjects
}
func initViewoPreviewLayer(videoGravity : AVLayerVideoGravity, orientation : AVCaptureVideoOrientation) {
assert(session != nil)
videoPreviewLayer = AVCaptureVideoPreviewLayer(session: session!)
videoPreviewLayer!.videoGravity = videoGravity
videoPreviewLayer!.connection!.videoOrientation = orientation
}
func addVideoLayerToImageView(imageView : UIImageView) {
assert(self.videoPreviewLayer != nil)
imageView.layer.addSublayer(self.videoPreviewLayer!)
self.videoPreviewLayer!.frame = imageView.bounds
}
func startSession() {
assert(session != nil)
self.session!.startRunning()
}
/*==========================================================================
STATIC FUNCTIONS
==========================================================================*/
static func getBackCamera() -> AVCaptureDevice {
return AVCaptureDevice.default(.builtInWideAngleCamera, for: AVMediaType.video, position: .back)!
}
static func getFrontCamera() -> AVCaptureDevice {
return AVCaptureDevice.default(.builtInWideAngleCamera, for: AVMediaType.video, position: .front)!
}
static func isCameraAvailable() -> Bool {
if #available(iOS 10.0, *) {
let count : Int = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera],
mediaType: AVMediaType.video,
position: .unspecified).devices.count
if count > 0 { return true }
}
else {
let count = AVCaptureDevice.devices(for: AVMediaType.video).count
if count > 0 { return true }
}
return false
}
/*==========================================================================
CAMERA BUILDER CLASS
==========================================================================*/
class Builder {
var cameraSource : CameraSource
init() {
cameraSource = CameraSource()
}
func createSession() -> Builder {
if (cameraSource.getSession() != nil) {
cameraSource.setSession(session: nil)
}
cameraSource.setSession(session: AVCaptureSession())
return self
}
func setSessionPreset(preset : AVCaptureSession.Preset) -> Builder {
assert(cameraSource.getSession() != nil)
cameraSource.getSession()!.sessionPreset = preset
return self
}
func attachInputDevice(camera : AVCaptureDevice) throws -> Builder {
try self.prepareInputDevice(camera: camera)
try self.addInputToSession()
assert(cameraSource.inputDevice != nil)
return self
}
func addOutputToSessionForMetaData() throws -> CameraSource {
cameraSource.setCaptureMetadataOutput()
assert(cameraSource.getSession() != nil && cameraSource.getCaptureMetadataOutput() != nil)
if !cameraSource.getSession()!.canAddOutput(cameraSource.getCaptureMetadataOutput()!) {
throw AppErrorCode.cameraError("Unable to attach output to camera session")
}
cameraSource.getSession()!.addOutput(cameraSource.getCaptureMetadataOutput()!)
return self.cameraSource
}
/*==========================================================================
BUILDER PRIVATE FUNCTIONS
==========================================================================*/
private func prepareInputDevice(camera : AVCaptureDevice) throws {
do {
let inputDevice = try AVCaptureDeviceInput(device: camera)
cameraSource.setInputDevice(inputDevice: inputDevice)
} catch let error as NSError {
print(error.localizedDescription)
throw AppErrorCode.cameraError("Unable to attach input to camera session")
}
}
private func addInputToSession() throws {
if(cameraSource.getSession() == nil) {
throw AppErrorCode.cameraError("Unable to create camera session")
}
assert(cameraSource.getInputDevice() != nil && cameraSource.getSession()!.canAddInput(cameraSource.getInputDevice()!))
cameraSource.getSession()!.addInput(cameraSource.getInputDevice()!)
}
}
}
My QR scanner Code looks like
import UIKit
import Foundation
import AVFoundation
protocol QRScannerDelegate {
func scannedData(_ scannedString : String)
}
class QRScanner : NSObject {
private var cameraSource : CameraSource?
var delegate : QRScannerDelegate?
func prepareCamera (delegate : QRScannerDelegate) throws -> QRScanner {
do {
self.delegate = delegate
self.cameraSource = try CameraSource
.Builder()
.createSession()
.setSessionPreset(preset: .photo)
.attachInputDevice(camera: CameraSource.getBackCamera())
.addOutputToSessionForMetaData()
self.cameraSource!.setMetadataObjects(metaObjects: [.qr], delegate: self as AVCaptureMetadataOutputObjectsDelegate)
} catch let err as NSError {
print(err.localizedDescription)
self.cameraSource = nil
throw AppErrorCode.cameraError("Unable to process camera with one or more issue")
}
return self
}
func initViewoPreviewLayer(videoGravity : AVLayerVideoGravity, orientation : AVCaptureVideoOrientation) -> QRScanner{
assert(cameraSource != nil)
self.cameraSource!.initViewoPreviewLayer(videoGravity: videoGravity, orientation: orientation)
return self
}
func addVideoLayerToImageView(imageView : UIImageView) -> QRScanner{
assert(cameraSource != nil)
self.cameraSource!.addVideoLayerToImageView(imageView: imageView)
return self
}
func startSession() {
assert(cameraSource != nil)
self.cameraSource!.startSession()
}
}
extension QRScanner : AVCaptureMetadataOutputObjectsDelegate {
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
print("Delegate called")
if metadataObjects.count == 0 {
self.delegate?.scannedData("No Data")
} else {
let metadataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
if metadataObj.type == AVMetadataObject.ObjectType.qr {
if metadataObj.stringValue != nil {
print("Scanner Getting data: \(metadataObj.stringValue!)")
self.delegate?.scannedData(metadataObj.stringValue!)
}
}
}
}
}
I have implemented the QRScannerDelegate in my ViewController but I am not getting anything in there. Moreover I am not getting callback inside AVCaptureMetadataOutputObjectsDelegate even.
I tried passing the ViewController instance as AVCaptureMetadataOutputObjectsDelegate then I was getting callback with the scanned info.
So My question is why is this happening?
1) When I am passing normal class as AVCaptureMetadataOutputObjectsDelegate I am not getting callback. But.
2) Whe I am passing UIViewController instance as AVCaptureMetadataOutputObjectsDelegate then I am able to get callback.
UPDATE
This is how I am calling prepareCamera from my View Controller
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
do {
try QRScanner().prepareCamera(delegate: self)
.initViewoPreviewLayer(videoGravity: .resizeAspectFill, orientation: .portrait)
.addVideoLayerToImageView(imageView: self.qrScannerImageView)
.startSession()
} catch {
print("Some Camera Error")
}
self.createOverlay()
}
Its hard to say for sure without knowing how you called prepareCamera as this is what triggers setMetadataObjectsDelegate but to me it looks like you may not be keeping a strong reference to QRScanner in your ViewController (instantiating it as in instance variable) Which could explain why the callback is getting hit when your ViewController is your AVCaptureMetadataOutputObjectsDelegate as the ViewController is still in memory.
It's also worth noting that if the ViewController is your QRScannerDelegate you will want to define delegate as weak var delegate : QRScannerDelegate? to prevent a memory leak.
EDIT:
Change
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
do {
try QRScanner().prepareCamera(delegate: self)
.initViewoPreviewLayer(videoGravity: .resizeAspectFill, orientation: .portrait)
.addVideoLayerToImageView(imageView: self.qrScannerImageView)
.startSession()
} catch {
print("Some Camera Error")
}
self.createOverlay()
}
to
var qrScanner = QRScanner()
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
do {
try self.qrScanner.prepareCamera(delegate: self)
.initViewoPreviewLayer(videoGravity: .resizeAspectFill, orientation: .portrait)
.addVideoLayerToImageView(imageView: self.qrScannerImageView)
.startSession()
} catch {
print("Some Camera Error")
}
self.createOverlay()
}
and change
protocol QRScannerDelegate {
func scannedData(_ scannedString : String)
}
to
protocol QRScannerDelegate: class {
func scannedData(_ scannedString : String)
}
To Allow a weak delegate
AVCaptureMetadataOutputObjectsDelegate is tough, but you can do some really cool stuff with it! So keep at it.
I pulled some QRScanner code I wrote a while ago and put it into a gist for you if you want to check it out. Its a bit more stripped down than what you have, but you may find it helpful.
https://gist.github.com/aChase55/733ea89af1bfa80c65971d3bc691f0b2

how to change url when button is pressed in swift

I'm having 2 buttons button1 & button2
when button1 is pressed I have to get url1 and when button2 is pressed get url2 in the below function
func fetchXMLData() {
XMLParserFactory.fetchData(url: "https://brwterrgn.ergwgw.com/etwtt.cms") { (listOfXMLVM, error) in
print("Fetch xml data")
if error == nil {
self.listOfNewsVM = listOfXMLVM!
self.tableView.reloadData()
}
else {
print(error?.localizedDescription ?? "Error")
}
}
}
}
Add parameter to this fetchXMLData function
func fetchXMLData(withUrl url: String)
also replace your url by this url variable
XMLParserFactory.fetchData(url: url)
Now in every IBAction call this function with different url passed as parameter of this method
#IBAction func button1pressed(_ sender: UIButton) {
fetchXMLData(withUrl: "url1.com")
}
#IBAction func button2pressed(_ sender: UIButton) {
fetchXMLData(withUrl: "url2.com")
}
You can try to make the url a parameter and change it from the caller place
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
fetchXMLData(url: "https://value.com/etwtt.cms")
}
func buttonAct(_ sender: UIButton) {
fetchXMLData(url: "https://brwterrgn.ergwgw.com/etwtt.cms")
}
func fetchXMLData(url:String) {
XMLParserFactory.fetchData(url:url) { (listOfXMLVM, error) in
print("Fetch xml data")
if error == nil {
self.listOfNewsVM = listOfXMLVM!
self.tableView.reloadData()
}
else {
print(error?.localizedDescription ?? "Error")
}
}
}
Edit
class FirstVC: UIViewController {
func showSecond(_ sender: UIButton) {
let sec = //
sec.delegate = self
present/push(sec)
}
func fetchXMLData(url:String) {
XMLParserFactory.fetchData(url:url) { (listOfXMLVM, error) in
print("Fetch xml data")
if error == nil {
self.listOfNewsVM = listOfXMLVM!
self.tableView.reloadData()
}
else {
print(error?.localizedDescription ?? "Error")
}
}
}
class SecondVC: UIViewController {
weak var delegate:FirstVC?
func buttonAct(_ sender: UIButton) {
delegate?.fetchXMLData(url: "https://brwterrgn.ergwgw.com/etwtt.cms")
}
}

Swift: netServiceBrowser didRemoveService MacOSX 10.13

I am trying to run a NetServiceBrowser. It will detect a new ZeroConf device as soon as it appears on the network. It doesn't however detect when the device is removed from the network.
netServiceBrowser(aNetServiceBrowser: NetServiceBrowser!, didRemoveService aNetService: NetService!, moreComing: Bool) is never called.
Am I missing something?
class BonjourDiscovery: NSObject, NetServiceBrowserDelegate, NetServiceDelegate
{
var browser: NetServiceBrowser
var services = [NetService]()
static let instance = BonjourDiscovery()
override init()
{
browser = NetServiceBrowser()
services = []
}
func startDiscovery()
{
browser.delegate = self
browser.searchForServices(ofType: "_smb._tcp.", inDomain: "")
}
func stopDiscovery()
{
browser.stop()
}
func netServiceBrowser(_ browser: NetServiceBrowser, didFind service: NetService, moreComing: Bool)
{
print ("Found:" + service.name)
self.services.append(service)
}
func netServiceBrowser(aNetServiceBrowser: NetServiceBrowser!, didRemoveService aNetService: NetService!, moreComing: Bool)
{
print ("Removed:" + aNetService.name)
if let index = services.index(of: aNetService)
{
services.remove(at: index)
}
}
}
For completeness I have posted the full answer, correcting the didRemoveService function definition (Thanks to Martin R):
class BonjourDiscovery: NSObject, NetServiceBrowserDelegate, NetServiceDelegate
{
var browser: NetServiceBrowser
var services = [NetService]()
static let instance = BonjourDiscovery()
override init()
{
browser = NetServiceBrowser()
services = []
}
func startDiscovery()
{
browser.delegate = self
browser.searchForServices(ofType: "_smb._tcp.", inDomain: "")
}
func stopDiscovery()
{
browser.stop()
}
func netServiceBrowser(_ browser: NetServiceBrowser, didFind service: NetService, moreComing: Bool)
{
print ("Found:" + service.name)
self.services.append(service)
}
func netServiceBrowser(_ browser: NetServiceBrowser, didRemove service: NetService, moreComing: Bool)
{
print ("Removed:" + service.name)
if let index = services.index(of: service)
{
services.remove(at: index)
}
}
}

Given login/signUp code by Parse.com, has binary operator error

I am making SignUp/SignIn pages with watching youtube video.
He makes these pages with parseUI,
In his video, there is no error, but I get an error which is
"binary operator "|" cannot be applied to two 'PFLoginFields' operands" (It is checked where in my code down there. )
I checked in parse.com, parse example code is exactly same code with his.
So my Question is
How can I fix this code to work properly?
or Is there any other Binary operator I can use instead of ||?
import UIKit
import Parse
import ParseUI
class NewResisterVC: UIViewController, PFLogInViewControllerDelegate, PFSignUpViewControllerDelegate {
var logInViewController : PFLogInViewController = PFLogInViewController()
var signUpViewController : PFSignUpViewController = PFSignUpViewController()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
if (PFUser.currentUser() == nil) {
/////////// HERE IS A PROBELM /////////////////
self.logInViewController.fields = (PFLogInFields.UsernameAndPassword | PFLogInFields.LogInButton | PFLogInFields.SignUpButton | PFLogInFields.PasswordForgotten | PFLogInFields.DismissButton)
//////////////////////////////////////////
var loginLogoTitle = UILabel()
loginLogoTitle.text = "bany"
self.logInViewController.logInView!.logo = loginLogoTitle
self.logInViewController.delegate = self
var signUpLogoTitle = UILabel()
signUpLogoTitle.text = "bany"
self.signUpViewController.signUpView!.logo = signUpLogoTitle
self.signUpViewController.delegate = self
self.logInViewController.signUpController = self.signUpViewController
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK: Parse Login
func logInViewController(logInController: PFLogInViewController, shouldBeginLogInWithUsername username: String, password: String) -> Bool {
if(!username.isEmpty || !password.isEmpty) {
return true
}else{
return false
}
}
func logInViewController(logInController: PFLogInViewController, didLogInUser user: PFUser) {
self.dismissViewControllerAnimated(true, completion: nil)
}
func logInViewController(logInController: PFLogInViewController, didFailToLogInWithError error: NSError?) {
print("Fail to login")
}
//MARK: Parse Sign Up
func signUpViewController(signUpController: PFSignUpViewController, didSignUpUser user: PFUser) {
self.dismissViewControllerAnimated(true, completion: nil)
}
func signUpViewController(signUpController: PFSignUpViewController, didFailToSignUpWithError error: NSError?) {
print("fail to sign up...")
}
func signUpViewControllerDidCancelSignUp(signUpController: PFSignUpViewController) {
print("User dismissed sign up")
}
// mark: Actions
#IBAction func simpleAction(send: AnyObject) {
self.presentViewController(self.logInViewController, animated: true, completion: nil)
}
}
The guy in video is using xcode 6 with swift 1.2, you are using xcode 7 with swift 2.0. Syntax has changed, you have to rewrite this line like this:
self.logInViewController.fields = [PFLogInFields.UsernameAndPassword,
PFLogInFields.LogInButton, PFLogInFields.SignUpButton,
PFLogInFields.PasswordForgotten, PFLogInFields.DismissButton]
Also note that you don't need to write typename prefix when assigning to variable:
self.logInViewController.fields = [.UsernameAndPassword, .LogInButton,
.SignUpButton, .PasswordForgotten, .DismissButton]