Swift check if class conforms to protocol always true - ios

protocol Device {
}
protocol ActiveDevice: Device {
}
protocol NoActive: Device {
}
ViewController:
class ViewController : UIViewController {
let device: Device
}
Setting device for ViewController. currentDevice is an object which conforms to protocol Device
vc.device = currentDevice as! ActiveDevice
Checking if it conforms to the protocol:
if let currentDevice = device as? NoActive {
print("Its not active device")
}else if let currentDevice = device as? ActiveDevice {
print("Its active device")
}else {
print("Its just a device")
}
It always prints Its not active device what I would expect in this case that it would print Its active device

Please check the following code and let me know if this helps.
protocol Device {
}
protocol ActiveDevice: Device {
}
protocol NoActive: Device {
}
// class TestDevice: Device {
// class TestDevice: ActiveDevice {
class TestDevice: NoActive {
}
let currentDevice = TestDevice()
// let device: Device = currentDevice as! ActiveDevice
(It threw error as "Could not cast value of type '__lldb_expr_9.TestDevice' (0x11a2f9090) to '__lldb_expr_9.ActiveDevice' (0x11a6d0628)."). We cannot do this.
let device: Device = currentDevice
if device is NoActive {
print("Its not active device")
}else if device is ActiveDevice {
print("Its active device")
}else {
print("Its just a device")
}
Now, the output is "Its not active device". And after changing the TestDevice to "ActiveDevice", it printed "Its active device" and so on.

Related

How to fetch SSID in iOS device with iOS 13

I have an Objective-C iPhone application and Currently I am using below code to get the connected Wifi name. But it is not working in iOS 13. How can I get the connected Wifi SSID in iOS 13?
Currently I am using the below code in Swift:
public class SSID {
class func fetch() -> String {
var currentSSID = ""
if let interfaces = CNCopySupportedInterfaces() {
for i in 0..<CFArrayGetCount(interfaces) {
let interfaceName = CFArrayGetValueAtIndex(interfaces, i)
let rec = unsafeBitCast(interfaceName, to: AnyObject.self)
let unsafeInterfaceData = CNCopyCurrentNetworkInfo("\(rec)" as CFString)
if let interfaceData = unsafeInterfaceData as? [String: AnyObject] {
currentSSID = interfaceData["SSID"] as! String
let BSSID = interfaceData["BSSID"] as! String
let SSIDDATA = interfaceData["SSIDDATA"] as! String
debugPrint("ssid=\(currentSSID), BSSID=\(BSSID), SSIDDATA=\(SSIDDATA)")
}
}
}
return currentSSID
}
}
But this code is returning nil in iOS 13, Thanks in advance!
Using the code provided on iOS 14 I got the following error:
nehelper sent invalid result code [1] for Wi-Fi information request
Searching for that error took me to this question
Solution:
The requesting app must meet one of the following requirements:
The app uses Core Location, and has the user’s authorization to use
location information.
The app uses the NEHotspotConfiguration API to configure the current
Wi-Fi network.
The app has active VPN configurations installed.
An app that fails to meet any of the above requirements receives the
following return value:
An app linked against iOS 12 or earlier receives a dictionary with
pseudo-values. In this case, the SSID is Wi-Fi (or WLAN in the China
region), and the BSSID is 00:00:00:00:00:00.
An app linked against iOS 13 or later receives NULL.
Important
To use this function, an app linked against iOS 12 or later must
enable the Access WiFi Information capability in Xcode.
I also confirmed that this in fact works on iOS 14 once you request location permission.
import CoreLocation
import UIKit
import SystemConfiguration.CaptiveNetwork
final class ViewController: UIViewController {
var locationManager: CLLocationManager?
override func viewDidLoad() {
super.viewDidLoad()
locationManager = CLLocationManager()
locationManager?.delegate = self
locationManager?.requestAlwaysAuthorization()
}
func getWiFiName() -> String? {
var ssid: String?
if let interfaces = CNCopySupportedInterfaces() as NSArray? {
for interface in interfaces {
if let interfaceInfo = CNCopyCurrentNetworkInfo(interface as! CFString) as NSDictionary? {
ssid = interfaceInfo[kCNNetworkInfoKeySSID as String] as? String
break
}
}
}
return ssid
}
}
extension ViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedAlways || status == .authorizedAlways {
let ssid = self.getWiFiName()
print("SSID: \(String(describing: ssid))")
}
}
}
Output: SSID: YaMomsWiFi
Don't forget to include the wifi entitlement, and the necessary keys in your plist for location permission.

Metal Device (MTLDevice) variable becomes nil after initialization

I have a renderer class in my Metal Swift (iOS/MacOS) project that is an MTKViewDelegate. I extract the MTLDevice using MTLCreateSystemDefaultDevice(), however after init, it becomes nil? I wonder if I've missed a quirk of Swift or Metal here. This is roughly how the code goes,
class Renderer: NSObject, MTKViewDelegate {
var device: MTLDevice!
​
init(metalView: MTKView) {
guard let device = MTLCreateSystemDefaultDevice() else
{
fatalError("GPU not available")
}
​ metalView.device = device
if device != nil {
print (“device not nil”)
}
}
​
func draw(in view: MTKView) {
if device == nil {
print (“device is nil here”)
}
}
}
In my ViewController I do
guard let metalView = view as? MTKView else {
fatalError("Metal View not setup")
}
renderer = Renderer(metalView: metalView)
What I see happen is:
device not nil
device is nil here
device is nil here
device is nil here
device is nil here
at 60hz on every draw call
EDIT: Edited code to make it clear that the device actually is being assigned to a variable in the global scope (metalView).
As per your code you are not assigning local device to implicitly unwrapped global device variable. Assign local device to global one to fix the issue.
guard let device = MTLCreateSystemDefaultDevice() else
{
fatalError("GPU not available")
}
self.device = device

Is this correct to check FaceID?

Sorry, unavailability of iPhone-X.
After the launch of iPhone-X, everyone wants their application should be compatible with iOS11 and with touchID but the problem is it's too expensive for a developer to test touch ID.
I don't have iPhone to check my code but can I check the same in iOS simulator?
let context = LAContext()
if ( context.biometryType == .typeFaceID ) {
// Face ID
}
if ( context.biometryType == .typeTouchID) {
// Touch ID
} else {
// Stone Age
}
You can test it without device also. Use simulator's Face ID to validate your code and it will behave similarly in iPhone-X also.
Simulator does not recognise a face but allows you to simulate a matching and non-matching faces, if you've enabled Enrolled option from Face ID.
Add following code to your view controller and try with Face-ID
import LocalAuthentication
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
localAuthentication()
}
func localAuthentication() -> Void {
let laContext = LAContext()
var error: NSError?
let biometricsPolicy = LAPolicy.deviceOwnerAuthenticationWithBiometrics
if (laContext.canEvaluatePolicy(biometricsPolicy, error: &error)) {
if let laError = error {
print("laError - \(laError)")
return
}
var localizedReason = "Unlock device"
if #available(iOS 11.0, *) {
if (laContext.biometryType == LABiometryType.faceID) {
localizedReason = "Unlock using Face ID"
print("FaceId support")
} else if (laContext.biometryType == LABiometryType.touchID) {
localizedReason = "Unlock using Touch ID"
print("TouchId support")
} else {
print("No Biometric support")
}
} else {
// Fallback on earlier versions
}
laContext.evaluatePolicy(biometricsPolicy, localizedReason: localizedReason, reply: { (isSuccess, error) in
DispatchQueue.main.async(execute: {
if let laError = error {
print("laError - \(laError)")
} else {
if isSuccess {
print("sucess")
} else {
print("failure")
}
}
})
})
}
}
}
FaceID authentication will prompt you for first time to allow FaceID detection for your app.
Now enable Face ID enrolment and run your app to test Face ID simulation Testing.
Here is simulation result for matching and non-matching faces.
Result for matching face:
Result for non-matching face:

Keep torch on while taking video iOS swift

I built a camera app for auto capture. I want to keep the flash on as long as the camera is on. I set the following code :
cameraDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
if (cameraDevice.hasTorch) {
do {
try cameraDevice.lockForConfiguration()
if cameraDevice.isTorchActive {
cameraDevice.torchMode = AVCaptureTorchMode.on
} else {
// sets the torch intensity to 100%
try cameraDevice.setTorchModeOnWithLevel(0.8)
}
cameraDevice.unlockForConfiguration()
} catch {
print(error)
}
}
But when I run the app, it only flashes for one time and then goes off. How can I solve this problem?
Call this method
Inside your camera active/Open func or When device camera active -
func flashActive() {
if let currentDevice = AVCaptureDevice.default(for: AVMediaType.video), currentDevice.hasTorch {
do {
try currentDevice.lockForConfiguration()
let torchOn = !currentDevice.isTorchActive
try currentDevice.setTorchModeOn(level:1.0)//Or whatever you want
currentDevice.torchMode = torchOn ? .on : .off
currentDevice.unlockForConfiguration()
} catch {
print("error")
}
}
}

Can a AVCaptureFileOutputRecordingDelegate be added to a subclass UIView?

I am having an issue creating a capture session in a custom UIView. I set the delegate like this
class Camera: UIView, AVCaptureFileOutputRecordingDelegate, AVAudioRecorderDelegate {
}
and then I set everything up and set the delegate like this
self.recordingDelegate? = self
captureSession.sessionPreset = AVCaptureSessionPresetHigh
let devices = AVCaptureDevice.devices()
for device in devices {
if (device.hasMediaType(AVMediaTypeVideo)) {
if(device.position == AVCaptureDevicePosition.Back) {
captureDevice = device as? AVCaptureDevice
if captureDevice != nil {
beginSession()
}
}
}
}
and all goes well. However, in the beginSession function:
func beginSession() {
let err : NSError? = nil
do {
self.captureSession.addInput(try AVCaptureDeviceInput(device: self.captureDevice!))
}
catch {
print("dang")
}
if err != nil {
print("error: \(err?.localizedDescription)")
}
...
The catch is thrown when I try to add the capture device input and there for it is not being added and I can not figure out why.
All of my code I am currently using was working fine before when I had it inside a UIViewController but when I switched it over to a subclass of UIView it stopped working. Any help would be appreciated if more code is needed let me know thank you!
I figured it out the iOS device I was using did not have the camera enabled for some reason there for the input could not be added which made the preview layer unable to capture any data

Resources