I’m new to RxSwift and I’m looking for a basic example of how to print in console live data streaming from an backend. I have a backend which is streaming some dummy data every 1 second, I can see it with a curl request and I want to be able to observe and subscribe and print it out in console automatically, please help!
I assume you are opening a socket connection to your server in order to receive live data. You can use RxWebSocket to handle this data flow. There are examples in the documentation/readme for the API.
https://github.com/daltoniam/Starscream/tree/master/examples/SimpleTest/SimpleTest
import UIKit
import Starscream
class ViewController: UIViewController, WebSocketDelegate {
var socket: WebSocket!
#IBOutlet weak var label: UILabel!
#IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
var request = URLRequest(url: URL(string: "wss://echo.websocket.org")!)
request.timeoutInterval = 5
socket = WebSocket(request: request)
socket.delegate = self
socket.connect()
}
// MARK: Websocket Delegate Methods.
func websocketDidConnect(socket: WebSocketClient) {
print("websocket is connected")
}
func websocketDidDisconnect(socket: WebSocketClient, error: Error?) {
if let e = error as? WSError {
print("websocket is disconnected: \(e.message)")
} else if let e = error {
print("websocket is disconnected: \(e.localizedDescription)")
} else {
print("websocket disconnected")
}
}
func websocketDidReceiveMessage(socket: WebSocketClient, text: String) {
self.label.text = text
print("Received text: \(text)")
}
func websocketDidReceiveData(socket: WebSocketClient, data: Data) {
print("Received data: \(data.count)")
}
// MARK: Write Text Action
#IBAction func send(_ sender: UIButton) {
socket.write(string: "Hello \(textField.text!)")
}
// MARK: Disconnect Action
#IBAction func disconnect(_ sender: UIBarButtonItem) {
if socket.isConnected {
sender.title = "Connect"
socket.disconnect()
} else {
sender.title = "Disconnect"
socket.connect()
}
}
}
extension URL {
init(staticString string: StaticString) {
guard let url = URL(string: "\(string)") else {
preconditionFailure("Invalid static URL string: \(string)")
}
self = url
}
}
Related
I'm trying to upgrade mi app to swift 4, but the barcode reader is not working.
I have isolated the barcode reader code, and still not working. The camera works but it does not detect the barcode.
The code worked just fine on swift 3 iOS 10.
This is the complete code
import AVFoundation
import UIKit
class ViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
var captureSession: AVCaptureSession!
var previewLayer: AVCaptureVideoPreviewLayer!
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.black
captureSession = AVCaptureSession()
let videoCaptureDevice = AVCaptureDevice.default(for: AVMediaType.video)
let videoInput: AVCaptureDeviceInput
do {
videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice!)
} catch {
return
}
if (captureSession.canAddInput(videoInput)) {
captureSession.addInput(videoInput)
} else {
failed();
return;
}
let metadataOutput = AVCaptureMetadataOutput()
if (captureSession.canAddOutput(metadataOutput)) {
captureSession.addOutput(metadataOutput)
metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
metadataOutput.metadataObjectTypes = [AVMetadataObject.ObjectType.ean8, AVMetadataObject.ObjectType.ean13, AVMetadataObject.ObjectType.pdf417]
} else {
failed()
return
}
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession);
previewLayer.frame = view.layer.bounds;
previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill;
view.layer.addSublayer(previewLayer);
captureSession.startRunning();
}
func failed() {
let ac = UIAlertController(title: "Scanning not supported", message: "Your device does not support scanning a code from an item. Please use a device with a camera.", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac, animated: true)
captureSession = nil
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if (captureSession?.isRunning == false) {
captureSession.startRunning();
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if (captureSession?.isRunning == true) {
captureSession.stopRunning();
}
}
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
captureSession.stopRunning()
if let metadataObject = metadataObjects.first {
let readableObject = metadataObject as! AVMetadataMachineReadableCodeObject;
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
found(code: readableObject.stringValue!);
}
dismiss(animated: true)
}
func found(code: String) {
print(code)
}
override var prefersStatusBarHidden: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
}
I am using iOS 11 on my iPhone, upgraded to beta 9.
Any idea? Thank you.
I figured it out but Apple didn't make it so obvious. The callback function from the delegate AVCaptureMetadataOutputObjectsDelegate has been renamed and the parameter names are different!
So, replace
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!)
to
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection)
My view controller is now scanning QR Codes as before after this. It has the same parameters but the first parameter name is different. Change the function and parameter names and build/run.
After changing the delegate call back :
From
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!)
To
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection)
I need to set all available types for metadataObjectTypes too as below-
output.metadataObjectTypes=output.availableMetadataObjectTypes
After changing your code from:
func metadataOutput(captureOutput: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {}
to:
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {}
everything works again.
You can use QRCodeScanner83 to scan barcodes:
import QRCodeScanner83
import AVFoundation
...
guard let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(identifier: "CodeScannerViewController") as? CodeScannerViewController else {
return
}
vc.callbackCodeScanned = { code in
print("SCANNED CODE: \(code)")
vc.dismiss(animated: true, completion: nil)
}
self.present(vc, animated: true, completion: nil)
If you need custom UI, then you can nest from CodeScannerViewController and set CodeScannerViewController.delegate to receive updates of the scanner state.
I'm trying to write a simple command line app that can display some info on a notification. But, the Delegate is not being called, and neither is the Notification and I'm not sure what's missing here.
Judging from my output, I think the whole problem stems from the AppDelegate not being instantiated. But I am creating one just before I show call showNotification.
What am I missing here?
src/main.swift
import Foundation
import AppKit
var sema = DispatchSemaphore( value: 0 )
let server: String = "http://jsonip.com"
let port: String = "80"
let path: String = "/"
let todoEndpoint: String = server + ":" + port + path
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let url = URL(string: todoEndpoint)!
let task = session.dataTask(with: url, completionHandler: {
(data, response, error) in
if error != nil {
print(error!.localizedDescription)
} else {
do {
if let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any]
{
print(json)
let ad = AppDelegate()
ad.showNotification(title: "Title", subtitle: "SubTitle", informativeText: String(describing: json))
sema.signal()
}
} catch {
print("error in JSONSerialization")
}
}
})
print("Resume Task")
task.resume()
print("Wait for Semaphore")
sema.wait()
src/AppDelegate.swift
import Cocoa
class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDelegate {
func applicationDidFinishLaunching(aNotification: Notification) {
NSUserNotificationCenter.default.delegate = self
print("Delegate Self")
}
// NSUserNotificationCenterDelegate implementation
private func userNotificationCenter(center: NSUserNotificationCenter!, didDeliverNotification notification: NSUserNotification!) {
//implementation
}
private func userNotificationCenter(center: NSUserNotificationCenter!, didActivateNotification notification: NSUserNotification!) {
//implementation
}
private func userNotificationCenter(center: NSUserNotificationCenter!, shouldPresentNotification notification: NSUserNotification!) -> Bool {
//implementation
return true
}
func showNotification(title: String, subtitle: String, informativeText: String) -> Void {
let notification: NSUserNotification = NSUserNotification()
print("Show Notification")
notification.title = title
notification.subtitle = subtitle
notification.informativeText = informativeText
//notification.contentImage = contentImage
notification.soundName = NSUserNotificationDefaultSoundName
NSUserNotificationCenter.default.deliver(notification)
print(notification.isPresented)
}
}
Output
Resume Task
Wait for Semaphore
["about": /about, "reject-fascism":
Impeach Trump!, "ip": 110.50.73.141, "Pro!": http://getjsonip.com]
Show Notification
false
Program ended with exit code: 0
I'm new to Swift, and trying my hands with UIWebView app that loads default url, with option to perform quick action and load a different url.
Problem is when I request the quick action url, code executes but the new url is not loading. So I'm missing something in the flow somewhere.
Here is the code:
import UIKit
import WebKit
class ViewController: UIViewController, UIWebViewDelegate {
#IBOutlet var webView: UIWebView!
override func loadView() {
super.loadView()
self.webView = UIWebView()
self.view = self.webView!
}
override func viewDidLoad() {
print("view did load")
super.viewDidLoad()
let url = NSURL(string: "google.com")
let req = NSURLRequest(URL:url!)
webView.loadRequest(req)
webView.delegate = self
}
func loadUrl2() {
loadView()
let url = NSURL(string: "example.com")
print(url)
let req = NSURLRequest(URL:url!)
self.webView!.loadRequest(req)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I was experimenting and added loadView to loadUrl2, as I was getting
fatal error: unexpectedly found nil while unwrapping an Optional value
before that.
Edited to Include loading secondary link:
Here are the changes and files you'll need to make to the App Delegate
enum ShortcutIdentifier: String {
case OpenNewLink
case OpenBetterLink
init?(fullIdentifier: String) {
guard let shortIdentifier = fullIdentifier.componentsSeparatedByString(".").last else {
return nil
}
self.init(rawValue: shortIdentifier)
}
}
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
if let shortcutItem = launchOptions?[UIApplicationLaunchOptionsAnnotationKey] as? UIApplicationShortcutItem {
handleShortcut(shortcutItem)
return false
}
return true
}
func application(application: UIApplication, performActionForShortcutItem shortcutItem: UIApplicationShortcutItem, completionHandler: (Bool) -> Void) {
completionHandler(handleShortcut(shortcutItem))
}
private func handleShortcut(shortcutItem: UIApplicationShortcutItem) -> Bool {
let shortcutType = shortcutItem.type
guard let ShortcutIdentifier = ShortcutIdentifier(fullIdentifier: shortcutType) else {
return false
}
return selectLinkForIdentifier(ShortcutIdentifier)
}
private func selectLinkForIdentifier(identifier: ShortcutIdentifier) -> Bool {
guard let mainView = self.window?.rootViewController as? ViewController else {
return false
}
switch identifier {
case .OpenNewLink:
mainView.urlString = "http://www.bing.com"
mainView.loadWebView(mainView.urlString)
return true
case.OpenBetterLink:
mainView.urlString = "http://www.duckduckgo.com"
mainView.loadWebView(mainView.urlString)
return true
}
}
I also made changes in the MainVC
class ViewController: UIViewController, UIWebViewDelegate {
#IBOutlet var webView: UIWebView!
var urlString: String? = nil
override func viewDidLoad() {
super.viewDidLoad()
setUpWebView()
webView.delegate = self
view.addSubview(webView)
}
func setUpWebView() {
webView = UIWebView()
webView.frame = CGRectMake(0, 0, view.frame.width, view.frame.height)
loadWebView(urlString)
}
func loadWebView(var urlString: String?) {
if urlString == nil {
urlString = "http://www.google.com"
}
let url = NSURL(string: urlString!)
let req = NSURLRequest(URL:url!)
webView.loadRequest(req)
}
}
Be sure to add NSAppTransportSecurity dictionary to your .plist and add NSAllowsArbitraryLoads key set to YES.
I tested it and it should work for you.
this is what i have so far:
import Foundation
import Parse
import UIKit
import Bolts
class SignUpViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var statusLabel: UILabel!
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
#IBOutlet weak var createAccountButton: UIButton!
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
emailTextField.delegate = self;
passwordTextField.delegate = self;
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func createAccountButtonPressed(sender: AnyObject) {
if verifyEmailDomain(self.emailTextField.text)
{
createAccount(self.emailTextField.text, password: self.passwordTextField.text)
}
else
{
//self.statusLabel.text = "Email domain is not valid.";
let alert = UIAlertView()
alert.title = "Invalid Email Domain"
alert.message = "Make sure you entered in your address correctly. If you did, ask your system about using PageMD! Thanks."
alert.addButtonWithTitle("Close")
alert.show()
}
}
func verifyEmailDomain(email: String) -> Bool
{
var isVerifiedDomain = false
let userDomain: String = (email.componentsSeparatedByString("#")).last!
//NSLog(userDomain)
let validDomainsFileLocation = NSBundle.mainBundle().pathForResource("ValidDomains", ofType: "txt")
var validDomainsFileContent = NSString(contentsOfFile: validDomainsFileLocation!, encoding: NSUTF8StringEncoding, error: nil)
// NSLog(validDomainsFileContent! as String)
let validDomains = validDomainsFileContent!.componentsSeparatedByString("\n")
for domain in validDomains
{
NSLog(domain as! NSString as String)
if userDomain == (domain as? NSString)
{
isVerifiedDomain = true
break
}
}
return isVerifiedDomain
}
func createAccount(email: String, password: String)
{
var newUser = PFUser()
newUser.username = email // We want the user to login only with their email.
newUser.email = email
newUser.password = password
newUser.signUpInBackgroundWithBlock { (succeeded: Bool, error: NSError?) -> Void in
if error == nil
{
// Account created successfully!
if succeeded == true
{
self.statusLabel.text = "Account created!"
}
}
else
{
if let errorField = error!.userInfo
{
self.statusLabel.text = (errorField["error"] as! NSString) as String
}
else
{
// No userInfo dictionary present
// Help from http://stackoverflow.com/questions/25381338/nsobject-anyobject-does-not-have-a-member-named-subscript-error-in-xcode
}
}
}
}
func textFieldShouldReturn(textField: UITextField) -> Bool
{
textField.resignFirstResponder()
return true;
}
}
when i run it i receive this in my terminal for xcode:
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)
and highlighted in green is:
var validDomainsFileContent = NSString(contentsOfFile: validDomainsFileLocation!, encoding: NSUTF8StringEncoding, error: nil)
what can i do to avoid this error?
I'm trying to create a login that uses the emailVerified feature from parse but I keep receiving this error and cant save the email to the core or send the verification email to the user. What can i do to make this code work and stop the error from coming up?
In that case, the file at validDominsfileContent wasn't found. You need to make sure that the file is included in your Bundle.
To do that, open the Bundle-Resources:
Project > App target > Build Phases > Copy bundle resources
There you save your file. Now it should be found by Swift.
I'm trying to setup a sign in page using parse and swift in Xcode but I keep getting an error with 'signInBackgroundWithBlock' how do I make this work?
I keep receiving the message
Cannot invoke 'signUpInBackgroundWithBlock' with an argument list of
type ((Bool!, NSError!) -> Void)
so far this is what I have and I just have an error with that part.
import UIKit
import Parse
class EmailLogin: UIViewController, UITextFieldDelegate {
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var statusLabel: UILabel!
#IBOutlet weak var createAccountButton: UIButton!
#IBOutlet weak var passwordTextField: UITextField!
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
emailTextField.delegate = self;
passwordTextField.delegate = self;
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func createAccountButtonPressed(sender: AnyObject)
{
if verifyEmailDomain(self.emailTextField.text)
{
createAccount(self.emailTextField.text, password: self.passwordTextField.text)
}
else
{
//self.statusLabel.text = "Email domain is not valid.";
let alert = UIAlertView()
alert.title = "Invalid Email Domain"
alert.message = "Make sure you entered in your address correctly. If you did, ask your system about using PageMD! Thanks."
alert.addButtonWithTitle("Close")
alert.show()
}
}
func verifyEmailDomain(email: String) -> Bool
{
var isVerifiedDomain = false
let userDomain: String = (email.componentsSeparatedByString("#")).last!
//NSLog(userDomain)
let validDomainsFileLocation = NSBundle.mainBundle().pathForResource("ValidDomains", ofType: "txt")
var validDomainsFileContent = NSString(contentsOfFile: validDomainsFileLocation!, encoding: NSUTF8StringEncoding, error: nil)
//NSLog(validDomainsFileContent!)
let validDomains = validDomainsFileContent!.componentsSeparatedByString("\n")
for domain in validDomains
{
NSLog(domain as! NSString as String)
if userDomain == (domain as! NSString)
{
isVerifiedDomain = true
break
}
}
return isVerifiedDomain
}
func createAccount(email: String, password: String)
{
var newUser = PFUser()
newUser.username = email // We want the user to login only with their email.
newUser.email = email
newUser.password = password
//this where i get my error//
newUser.signUpInBackgroundWithBlock { (succeeded: Bool!, error: NSError!) -> Void in
if error == nil
{
// Account created successfully!
if succeeded == true
{
self.statusLabel.text = "Account created!"
}
}
else
{
if let errorField = error.userInfo
{
self.statusLabel.text = (errorField["error"] as NSString)
}
else
{
// No userInfo dictionary present
// Help from http://stackoverflow.com/questions/25381338/nsobject-anyobject-does-not-have-a-member-named-subscript-error-in-xcode
}
}
}
}
func textFieldShouldReturn(textField: UITextField) -> Bool
{
textField.resignFirstResponder()
return true;
}
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
If you are using swift 1.2 (Xcode 6.3) you need to call the function by:
newUser.signUpInBackgroundWithBlock({(succeeded:Bool, error:NSError?) -> Void in
})
And if you are using swift 1.1 (Xcode 6.1, 6.2) you need to call the function by:
newUser.signUpInBackgroundWithBlock({(succeded:Bool, error:NSError!) -> Void in
})
This is different because of the swift update 1.2 which has changes with using optionals.
Another way is to write it like this:
(Works in old and new swift)
newuser.signUpInBackgroundWithBlock { (succeded, error) -> Void in
}