How to find printers on IOS from Brother SDK? - ios

I find printers from iPad setting print can find my Brother printer.
But when I try the code I get empty device list and I don't know why.
I am not familiar with Swift. I just try the sample code from Official documentation.
https://support.brother.com/g/s/es/htmldoc/mobilesdk/guide/discover-printer.html
Here is my code:
func getPrinter() {
let printerManager = BRPtouchNetworkManager()
printerManager.setPrinterName("Brother QL-720NW")
printerManager.startSearch(5)
printerManager.getPrinterNetInfo()
print("start")
let testFind = YourClass()
print("1")
testFind.startSearchWiFiPrinter()
testFind.didFinishSearch(printerManager)
print("2")
}
class YourClass: NSObject, BRPtouchNetworkDelegate {
private var networkManager: BRPtouchNetworkManager?
func startSearchWiFiPrinter() {
print("3")
let manager = BRPtouchNetworkManager()
manager.delegate = self
manager.startSearch(5)
self.networkManager = manager
}
// BRPtouchNetworkDelegate
func didFinishSearch(_ sender: Any!) {
print("4")
guard let manager = sender as? BRPtouchNetworkManager else {
print("5")
return
}
guard let devices = manager.getPrinterNetInfo() else {
print("6")
return
}
print(devices)
print("7")
for deviceInfo in devices {
print("8")
if let deviceInfo = deviceInfo as? BRPtouchDeviceInfo {
print("Model: \(deviceInfo.strModelName), IP Address: \(deviceInfo.strIPAddress)")
}
}
}
}
I call my function getPrinter() and here is my print log:

The SDK documentation gives you an example implementation of two methods:
func startSearchWiFiPrinter() {}
and
func didFinishSearch(_ sender: Any!) {}
In the class you want to execute the search you must implement these. You also need to declare the class to attend the protocol BRPtouchNetworkDelegate. The last thing is to have a property to be able to hold the Network manager (Which is done in the line: private var networkManager: BRPtouchNetworkManager?)
However, you are not supposed to call the "didFinishSearch" method by yourself. When you call startSearchWiFiPrinter, the search begins, and the BRPtouchNetworkManager instance itself calls the didFinishSearch method. It is capable of doing so because you set the delegate in the line: manager.delegate = self.
You should not need 2 classes for this. You should not use 2 instances of BRPtouchNetworkManager either.
Try this. Remember the number you put as an argument to startSearchWiFiPrinter means how long in seconds the search will be.
class EXAMPLEClass: NSObject, BRPtouchNetworkDelegate {
private var networkManager: BRPtouchNetworkManager?
func getPrinter() {
self.startSearchWiFiPrinter()
}
func startSearchWiFiPrinter() {
let manager = BRPtouchNetworkManager()
manager.delegate = self
manager.setPrinterName("Brother QL-720NW")
manager.startSearch(5)
self.networkManager = manager
}
// BRPtouchNetworkDelegate
func didFinishSearch(_ sender: Any!) {
print("4")
guard let manager = sender as? BRPtouchNetworkManager else {
print("5")
return
}
guard let devices = manager.getPrinterNetInfo() else {
print("6")
return
}
print(devices)
print("7")
for deviceInfo in devices {
print("8")
if let deviceInfo = deviceInfo as? BRPtouchDeviceInfo {
print("Model: \(deviceInfo.strModelName), IP Address: \(deviceInfo.strIPAddress)")
}
}
}
}

Related

how to manage a several asynchronous task before doing some action?

I am beginner in programming. I actually have my own answer of this questions and the app worked as I am expected, but I am not sure if this is the correct way to to this.
This check out action will be triggered after the user click chechoutButton. but before before this chechoutButton.isEnabled , I have to make sure 3 parameters are available (not nil). before doing this check out action, I need 3 parameters :
get user's coordinate from GPS.
get user's location address from Google Place
API
Get current date time from server for verification.
method to get user location address from Google Place API will be triggered only if I get the coordinate from GPS, and as we know, fetching data from the internet (to take date and time) also takes time, it should be done asynchronously.
how do I manage this checkoutButton only enabled if those 3 parameters are not nil ? Is there a better way according to apple guideline to do this
the simplified code are below
class CheckoutTVC: UITableViewController {
#IBOutlet weak var checkOutButton: DesignableButton!
var checkinAndCheckoutData : [String:Any]? // from MainMenuVC
var dateTimeNowFromServer : String?
var userLocationAddress : String?
let locationManager = LocationManager()
var coordinateUser : Coordinate? {
didSet {
getLocationAddress()
}
}
override func viewDidLoad() {
super.viewDidLoad()
// initial state
checkOutButton.alpha = 0.4
checkOutButton.isEnabled = false
getDateTimeFromServer()
getCoordinate()
}
#IBAction func CheckoutButtonDidPressed(_ sender: Any) {
}
}
extension CheckoutTVC {
func getDateTimeFromServer() {
activityIndicator.startAnimating()
NetworkingService.getDateTimeFromServer { (result) in
switch result {
case .failure(let error) :
self.activityIndicator.stopAnimating()
// show alert
case .success(let timeFromServer) :
let stringDateTimeServer = timeFromServer as! String
self.dateTimeNowFromServer = stringDateTimeServer
self.activityIndicator.stopAnimating()
}
}
}
func getCoordinate() {
locationManager.getPermission()
locationManager.didGetLocation = { [weak self] userCoordinate in
self?.coordinateUser = userCoordinate
self?.activateCheckOutButton()
}
}
func getLocationAddress() {
guard let coordinateTheUser = coordinateUser else {return}
let latlng = "\(coordinateTheUser.latitude),\(coordinateTheUser.longitude)"
let request = URLRequest(url: url!)
Alamofire.request(request).responseJSON { (response) in
switch response.result {
case .failure(let error) :// show alert
case .success(let value) :
let json = JSON(value)
let locationOfUser = json["results"][0]["formatted_address"].string
self.userLocationAddress = locationOfUser
self.locationAddressLabel.text = locationOfUser
self.activateNextStepButton()
}
}
}
func activateCheckoutButton() {
if dateTimeNowFromServer != nil && userLocationAddress != nil {
checkOutButton.alpha = 1
checkOutButton.isEnabled = true
}
}
}
I manage this by using this method, but I don't know if this is the correct way or not
func activateCheckoutButton() {
if dateTimeNowFromServer != nil && userLocationAddress != nil {
checkOutButton.alpha = 1
checkOutButton.isEnabled = true
}
}
You can use DispatchGroup to know when all of your asynchronous calls are complete.
func notifyMeAfter3Calls() {
let dispatch = DispatchGroup()
dispatch.enter()
API.call1() { (data1)
API.call2(data1) { (data2)
//DO SOMETHING WITH RESPONSE
dispatch.leave()
}
}
dispatch.enter()
API.call3() { (data)
//DO SOMETHING WITH RESPONSE
dispatch.leave()
}
dispatch.notify(queue: DispatchQueue.main) {
finished?(dispatchSuccess)
}
}
You must have an equal amount of enter() and leave() calls. Once all of the leave() calls are made, the code in DispatchGroupd.notify will be called.

Swift: Array of base class does not call subclass function implementation

I'm trying to inject a fake instance into a unit test for a class depending on SimplePing, a NSObject subclass. My class has a property var simplePings: [SimplePing] which in my unit test I set as an array of FakeSimplePing. However, when the class goes in the array and calls simplePing.start(), it calls the SimplePing.start implementation instead of FakeSimplePing's, even though when I debug I see that the instance type is FakeSimplePing.
When the property is just a single SimplePing, the unit test uses the FakeSimplePing.start and the test passes. Does this have something to do with Swift and arrays of superclasses?
class Pinger : NSObject {
private var simplePings: [SimplePing] = []
func pingLocation(location: Location) -> Signal<Double, NoError> {
let simplePings = location.serverIPs.map { (serverIP: String) -> SimplePing in
let simplePing = SimplePing(hostName: serverIP)
simplePing?.delegate = self
return simplePing
}
configureDependencies(simplePings)
simplePings.forEach { $0.start() }
return signal
}
func configureDependencies(simplePings: [SimplePing]) {
if self.simplePings.isEmpty {
self.simplePings = simplePings
}
}
}
class FakeSimplePing: SimplePing {
var receivedStart = false
var receivedSendPingWithData = false
var fakeHostName: String!
override var hostName: String {
return fakeHostName
}
convenience init(hostName: String) {
self.init()
fakeHostName = hostName
}
override func start() {
// This does not get called
receivedStart = true
delegate?.simplePing?(self, didStartWithAddress: nil)
delegate?.simplePing?(self, didReceivePingResponsePacket: nil)
}
override func sendPingWithData(data: NSData!) {
receivedSendPingWithData = true
}
}
And the failing test:
beforeEach {
fakeSimplePing = FakeSimplePing(hostName: serverIP)
fakeSimplePing.delegate = pinger
pinger.configureDependencies([fakeSimplePing])
}
it("pings server with data") {
pinger.pingLocation(location)
expect(fakeSimplePing.receivedSendPingWithData).toEventually(beTrue())
}
The problem (I believe...) is in the naming in pingLocation
in the line
let simplePings = location.serverIPs.map { ....
you use the same name as of your property
private var simplePings: [SimplePing] = []
so you may think you're defining a new variable with the let, but actually, you may just use your property and change it on the way, so it got changed to SimplePing array, as it returns from the map
try to change your method into:
func pingLocation(location: Location) -> Signal<Double, NoError> {
let tempSimplePings = location.serverIPs.map { (serverIP: String) -> SimplePing in
let simplePing = SimplePing(hostName: serverIP)
simplePing?.delegate = self
return simplePing
}
configureDependencies(tempSimplePings)
simplePings.forEach { $0.start() }
return signal
}

Displaying SSID in iOS App using Swift

I'm currently trying to display the SSID of a user's connected WiFi and compare it to a particular SSID, for example, the set SSID is 'WirelessHotspot'.
When the user's connected WiFi is 'WirelessHotspot', the app will display that it is connected to the correct WiFi and also display the WiFi name.
Currently, I have tried this code, referenced from Get SSID in Swift 2:
import UIKit
import Foundation
import SystemConfiguration.CaptiveNetwork
public class SSID {
class func fetchSSIDInfo() -> String {
var currentSSID = ""
if let interfaces:CFArray! = CNCopySupportedInterfaces() {
for i in 0..<CFArrayGetCount(interfaces){
let interfaceName: UnsafePointer<Void> = CFArrayGetValueAtIndex(interfaces, i)
let rec = unsafeBitCast(interfaceName, AnyObject.self)
let unsafeInterfaceData = CNCopyCurrentNetworkInfo("\(rec)")
if unsafeInterfaceData != nil {
let interfaceData = unsafeInterfaceData! as Dictionary!
currentSSID = interfaceData["SSID"] as! String
}
}
self.networkname.text = String(currentSSID)
}
return currentSSID
}
}
class AttendanceScreen: UIViewController {
#IBOutlet weak var networkname: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
However, this code:
self.networkname.text = String(currentSSID)
Will return error:
Type 'SSID' has no member 'networkname'
So, how can I implement this in Swift for iOS 9? Thanks in advance!
I figured out that it would be much easier to create a bridge from Swift to Objective-C.
Importing framework:
#import <SystemConfiguration/CaptiveNetwork.h>
Code to get the SSID of user's connected WiFi:
func getMAC()->(success:Bool,ssid:String,mac:String){
if let cfa: NSArray = CNCopySupportedInterfaces() {
for x in cfa {
if let dict = CFBridgingRetain(CNCopyCurrentNetworkInfo(x as! CFString)) {
let ssid = dict ["SSID"]!
let mac = dict["BSSID"]!
return (true, ssid as! String, mac as! String)
}
}
}
return (false,"","")
}
Print and display in a label when needed:
let x = getMAC()
if x.success {
MAClabel = x.mac
SSIDlabel = x.ssid
print(x.mac)
print (x.ssid)
}
I hope that those with this question would find this useful!

How to call static method provided by protocol in Swift

How to access to static protocol method within a instance
I have a list of Contact, the contact can be a FamilyContact that inherit from Contact and the GroupStatus protocol
I want to call the static method from GroupStatus but in vain...
Here is my code
protocol GroupStatus {
static func isPrivate() -> Bool // static method that indicates the status
}
protocol IsBusy {
func wizzIt()
}
class AdresseBook {
private var contacts = [Contact]()
func addOne(c: Contact) {
contacts.append(c)
}
func listNonPrivated() -> [Contact]? {
var nonPrivateContact = [Contact]()
for contact in contacts {
// here is I should call the static method provided by the protocol
if self is GroupStatus {
let isPrivate = contact.dynamicType.isPrivate()
if !isPrivate {
nonPrivateContact.append(contact)
}
}
nonPrivateContact.append(contact)
}
return nonPrivateContact
}
}
class Contact : Printable {
var name: String
init(name: String) {
self.name = name
}
func wizz() -> Bool {
if let obj = self as? IsBusy {
obj.wizzIt()
return true
}
return false
}
var description: String {
return self.name
}
}
class FamilyContact: Contact, GroupStatus {
static func isPrivate() -> Bool {
return true
}
}
I can't compile Contact.Type does not have a member named 'isPrivate'
How can I call it ? It works if I delete the static keyword, but I think is more logical to define it static.
If I replace
let isPrivate = contact.dynamicType.isPrivate()
by
let isPrivate = FamilyContact.isPrivate()
It works, but I can have more than 1 subclasses
If I remove the static keywork I can do it by this way :
if let c = contact as? GroupStatus {
if !c.isPrivate() {
nonPrivateContact.append(contact)
}
}
But I want to keep the static keyword
This looks like a bug or a non-supported feature. I would expect that
the following works:
if let gsType = contact.dynamicType as? GroupStatus.Type {
if gsType.isPrivate() {
// ...
}
}
However, it does not compile:
error: accessing members of protocol type value 'GroupStatus.Type' is unimplemented
It does compile with FamilyContact.Type instead of GroupStatus.Type. A similar problem is reported here:
Swift 1.1 and 1.2: accessing members of protocol type value XXX.Type' is unimplemented
Making isPrivate() an instance method instead of a class method is
the only workaround that I currently can think of, maybe someone comes
with a better solution ...
Update for Swift 2 / Xcode 7: As #Tankista noted below, this has
been fixed. The above code compiles and works as expected in Xcode 7 beta 3.
type(of: contact).isPrivate()
This should work in recent Swift.

Check if AnyObject is of generic type in Swift

Let's say that I have generic class Bus:
class Bus<T> {
func doSomething() {}
}
and I can create instance of it:
var myBus = Bus<String>()
Now I have a function that takes one parameter of the AnyObject and tests it's type:
func checkType(object: AnyObject) {
if let foo = object as? String {
println("string")
}
}
My problem is that I can't see a way to check if object is of type Bus and run function doSomething() if it is of type Bus. Any help would be appreciated.
Edit: Protocols also don't seem to solve this the way they should.
import Foundation
#objc protocol BusProtocol {
func doSomething() -> Void
}
class Bus<T> : BusProtocol {
func doSomething() -> Void {
println("asdf")
}
}
func checkType(object: AnyObject) {
if let foo = object as? Bus<AnyObject> {
foo.doSomething() // no match
}
if let foo = object as? Bus<Any> {
foo.doSomething() // no match
}
if let foo = object as? Bus<String> {
foo.doSomething() // prints "asdf"
}
if let foo = object as? BusProtocol {
foo.doSomething() // SIGABRT -- -[SwiftObject doesNotRecognizeSelector:]
}
}
checkType(Bus<String>())
The problem here is your thinking of Bus as a concrete thing. It really isn't. Bus<String> is. Bus<Int> is too. But Bus isn't, at least not in the same sense. You need to know what T is.
Really, what you want is to write something like this:
func checkType<T>(object: AnyObject) {
if let foo = object as? Bus<T> {
println("Bus<T>")
}
}
But if you try and use it, you'll get an error:
// error: Argument for generic parameter 'T' could not be inferred.
checkType(myBus)
Unlike in other languages, you can't write checkType<String>(myBus). But the following might do what you're looking for:
func checkType<T>(object: AnyObject, T.Type) {
if let foo = object as? Bus<T> {
println("Bus<T>")
}
}
checkType(myBus,String.self)
This fixes what T is for any Bus<T> and will work correctly.
You might object that you don't want to specify what T is. However, instead, this leads to the question... once you've figured out that object is some kind of Bus, what are you going to do then? Are you planning on calling methods on it, or passing it as an argument to other functions? Chances are what you're trying to achieve can be better done with a generic function and protocol constraints, rather than using AnyObject and casting.
In swift 2.x you can use a protocol to achieve this, as you attempted without error:
protocol Busish {
func doSomething() -> Void
}
class Bus<T> : Busish {
func doSomething() {
print(self)
}
}
func with_any_bus(obj:AnyObject) {
if let b = obj as? Busish {
b.doSomething()
}
}
with_any_bus(Bus<Int>());
with_any_bus(Bus<String>());
output:
swiftblah.Bus<Swift.Int>
swiftblah.Bus<Swift.String>
This may or may not be helpful to you specifically, since you seem to be using 1.2, but maybe someone else who stumbles on this question will find it useful.
You've practically got it.
func checkType(object: AnyObject) {
if let foo = object as? Bus<AnyObject> {
print("Got here")
} else {
print("Fail")
}
}
let bus = Bus<String>()
checkType(bus) // Fail
let otherBus = Bus<AnyObject>()
checkType(otherBus) // "Got Here"
I know that's not really what you want, but it shows what Swift needs.

Resources