Posts

Post not yet marked as solved
0 Replies
3 Views
I am implementing pan and zoom features for an app using a custom USB camera device, in iPadOS. I am using an update function (shown below) to apply transforms for scale and translation but they are not working. By re-enabling the animation I can see that the scale translation seems to initially take effect but then the image animates back to its original scale. This all happens in a fraction of a second but I can see it. The translation transform seems to have no effect at all. Printing out the value of AVCaptureVideoPreviewLayer.transform before and after does show that my values have been applied. private func updateTransform() { #if false // Disable default animation. CATransaction.begin() CATransaction.setDisableActions(true) defer { CATransaction.commit() } #endif // Apply the transform. logger.debug("\(String(describing: self.videoPreviewLayer.transform))") let transform = CATransform3DIdentity let translate = CATransform3DTranslate(transform, translationX, translationY, 0) let scale = CATransform3DScale(transform, scale, scale, 1) videoPreviewLayer.transform = CATransform3DConcat(translate, scale) logger.debug("\(String(describing: self.videoPreviewLayer.transform))") } My question is this, how can I properly implement pan/zoom for an AVCaptureVideoPreviewLayer? Or even better, if you see a problem with my current approach or understand why the transforms I am applying do not work, please share that information.
Posted Last updated
.
Post not yet marked as solved
0 Replies
136 Views
I am trying to create a near real-time drawing of waveform data from within a SwiftUI app. The data is streaming in from the hardware and I've verified that the draw(in ctx: CGContext) override in my custom CALayer is getting called. I have added this custom CALayer class as a sublayer to a UIView instance that I am making available via the UIViewRepresentable protocol. The only time I see updated output from the CALayer is when I rotate the device and layout happens (I assume). How can I force SwiftUI to update every time I render new data in my CALayer? More Info: I'm porting an app from the Windows desktop. Previously, I tried to make this work by simply generating a new UIImage from a CGContext every time I wanted to update the display. I quickly exhausted memory with that technique because a new context is being created every time I call UIGraphicsImageRenderer(size:).image { context in }. What I really wanted was something equivalent to a GDI WritableBitmap. Apparently this animal allows a programmer to continuously update and re-use the contents. I could not figure out how to do this in Swift without dropping down to the old CGBitmapContext stuff written in C and even then I wasn't sure if that would give me a reusable context that I could output in SwiftUI each time I refreshed it. CALayer seemed like the answer. I welcome any feedback on a better way to do what I'm trying to accomplish.
Posted Last updated
.
Post not yet marked as solved
1 Replies
511 Views
I have a custom USB device that includes a microphone. I can see the microphone on macOS when I plug in the device so I know that it is working with the kernel and AV subsystems. I can enumerate and reference the microphone using AVCaptureDevice but I have not been able to figure out how to use this device reference with AVAudioEngine. I'm trying to accomplish two things with this microphone. I want to stream audio from the microphone and have it rendered to the speakers on my MacBook Pro. I want to capture sound data from the microphone and forward it to a live streaming API. To my mind, from what I've read, I need AVAudioEngine to do this but I'm having trouble determining from the documentation just how to go about it on macOS. It seems that there is a lot more information for iOS or iPadOS but since USB-C support is sparsely documented on those operating systems, I'm focusing on the desktop (macOS) for now. Can I convert an AVCaptureDevice into and audio input for AVAudioEngine? If not, how can I accomplish what I'm trying to do using whatever is available on AVFoundation?
Posted Last updated
.
Post marked as solved
2 Replies
226 Views
I have an app that loads a DEXT (driver). This app includes a settings bundle that allows me to activate/deactivate the driver. When I issue the API call to activate the driver, iOS switches to the Settings app and displays the page for my DEXT loading application but the switch to enable the driver, which is part of my settings bundle, does not appear. I'm using this API call: OSSystemExtensionRequest.activationRequest(forExtensionWithIdentifier: "driver-id", queue: .main) Here are the contents of my settings bundle Root.plist: ` Here are the contents of my Root.strings file: "Group" = "Group"; "Name" = "Name"; "none given" = "none given"; "Enabled" = "Enabled";
Posted Last updated
.
Post marked as solved
2 Replies
503 Views
According to Apple's documentation USBDriverKit for iPadOS has been available since DriverKit 19 and the M1 iPad were released. However, using Xcode 15.0.1, I am unable to link to or even find USBDriverKit from within Xcode. Is the documentation incorrect? If not what do I need to do in order to access and leverage USBDriverKit? From what I've read, USBSerialDriverKit is not available. As I have a USB based serial device that I want to use from the iPad, the next obvious step is to write my own USB device extension using USBDriverKit as a provider. If you have experience with this and can definitively say whether or not what I'm attempting is even within the realm of possibility, please chime in. Thanks. -Michael
Posted Last updated
.
Post not yet marked as solved
0 Replies
526 Views
I wanted to access the users contacts from within my SwiftUI app. Unfortunately, the statement: import ContactsUI Produces the following error: No such module ‘ContactsUI’ Should I be able to import this module?
Posted Last updated
.
Post marked as solved
1 Replies
1.3k Views
I'm experimenting with async/await on some existing code and would like to cancel an async thumbnail download if the table-view cell needs to be re-used. The problem is that I don't know how to declare storage for the handle so I can cancel it later on. See the attached code. class PhotoCell: UITableViewCell {     @IBOutlet weak var albumLabel: UILabel!     @IBOutlet weak var photoIdLabel: UILabel!     @IBOutlet weak var thumbnailImageView: UIImageView!     @IBOutlet weak var titleLabel: UILabel!     private static var imageLoader = ImageLoader() //    private var task: Handle<(), Never>?     override func prepareForReuse() { //        task?.cancel()         albumLabel.text = ""         titleLabel.text = ""         photoIdLabel.text = ""     }     // MARK: - Public Methods     func configure(with photo: JPPhoto) {         albumLabel.text = "#\(photo.albumId.rawValue)"         titleLabel.text = photo.title photoIdLabel.text = "#\(photo.id.rawValue)"         thumbnailImageView.image = UIImage(systemName: "photo")         /* task = */async {             if let image = await PhotoCell.imageLoader.loadImage(from: photo.thumbnailUrl) {                 thumbnailImageView.image = image             }         }     } }
Posted Last updated
.
Post not yet marked as solved
3 Replies
765 Views
Ok, the setup for this is pretty complex. I'm doing maintenance on an app I did not write. The view structure is as follows: At the base you have a UICollectionViewController. Each UICollectionViewCell has an assigned UIViewController within it. Each of these controllers is attached to the view hierarchy as a child view controller. The main view of one of these child controllers is a UITableView/UIViewController pair. Everything seems to be hooked up properly and working well except for one case. Assuming the table-view has more than two rows, If I swipe-left to delete the second row (IndexPath 0,1), the content or row one (IndexPath 0,0) goes blank. I can see the disclosure accessory view but the two UILabels up and disappear. If I tap on the blank row the tap behavior is still intact. If I refresh the table-view, the missing content appears as it should. To make things a little more interesting, this table-view is implement using RxSwift. Here is the code: private func bind() {         // Cell for row at index path.         let curriedArgument: (Int, Assignment, AssessmentTableViewCell) - Void = { /* rowIndex */_, model, cell in             cell.assignment = model         }         let observer: Observable[Assignment]         // For the widget version of this controller, only display the first N         // items in a table-view that does not scroll. If more than N items exist         // the user must tap the `More` view. For the non-widget view, show all         // available items in a scrolling table-view.         if isWidget {             tableView.isScrollEnabled = false             observer = viewModel                 .assignments                 .asObservable()                 .map({ Array($0.prefix(CPAssignmentWidgetVC.numberOfItemsToDisplay))})         } else {             observer = viewModel                 .assignments                 .asObservable()         }         observer             .distinctUntilChanged()             .bind(to: tableView.rx.items(cellIdentifier: "AssessmentCell"), curriedArgument: curriedArgument)             .disposed(by: disposeBag)         // When something changes, update both the widget and the modal view as         // needed.         if isWidget {             Observable                 .combineLatest(viewModel.fetching.asObservable(),                                viewModel.assignments.asObservable())                 .subscribe(onNext: { [weak self] (isFetching, assignments) in                     self?.updateFooter(with: assignments, isFetching: isFetching)                 })                 .disposed(by: disposeBag)         } else {             viewModel.fetching.asObservable()                 .distinctUntilChanged()                 .debounce(.milliseconds(500), scheduler: MainScheduler.instance)                 .subscribe(onNext: { isFetching in                     if isFetching {                         SVProgressHUD.show()                     } else {                         SVProgressHUD.dismiss()                     }                 })                 .disposed(by: disposeBag)         }         // Select cell         tableView             .rx             .itemSelected             .subscribe(onNext: { [unowned self] indexPath in                 self.tableView.deselectRow(at: indexPath, animated: true)                 guard                     let cell = tableView.cellForRow(at: indexPath) as? AssessmentTableViewCell,                     let assignment = cell.assignment else { return }                 if cell.assignmentResult != nil {                     presentOptions(cell)                 } else {                     guard let patient = patient, patient.hasPermissionToModify(permissionType: .assessments) else {                         let title = NSLocalizedString("We're sorry!", comment: "Notification error title")                         let message = NSLocalizedString("You don't have permission to complete this survey", comment: "Notification error message")                         let dismiss = NSLocalizedString("Dismiss", comment: "Button title")                         LHDNotification.show(with: title, text: message, type: .error).setDismissButtonTitle(dismiss)                         return                     }                     presentAssignmentEntryForm(assignment)                 }             })             .disposed(by: disposeBag)         // Delete cell (remove associated backing model value)         tableView             .rx             .itemDeleted             .subscribe(onNext: { indexPath in                 self.viewModel.remove(at: indexPath.row)             })             .disposed(by: disposeBag)         // Display last cell         tableView             .rx             .willDisplayCell             .subscribe(onNext: { [unowned self] (/* cell */_, indexPath) in                 if indexPath.item + 1 == self.viewModel.numberOfItems {                     self.viewModel.loadMore()                 }             })             .disposed(by: disposeBag)     } } Question: Why is the first row content being wiped out? Assuming no one can know the answer to this I have a follow-up question. How can I get the contents of the entire tableview to redraw themselves after a successful delete? I would have assumed the binding to the table-view on line 27 would handle this automatically when the view-model updates.
Posted Last updated
.
Post not yet marked as solved
1 Replies
2.2k Views
import Foundation import os.log extension OSLog { private static var subsystem = Bundle.main.bundleIdentifier! static let session = OSLog(subsystem: subsystem, category: "session") static func Debug(_ s: StaticString, args: CVarArg...) { os_log(s, log: OSLog.session, type: .debug, args) } static func Error(_ s: StaticString, args: CVarArg...) { os_log(s, log: OSLog.session, type: .error, args) } static func Info(_ s: StaticString, args: CVarArg...) { os_log(s, log: OSLog.session, type: .info, args) } }I defined this extension for using OSLog instead of NSLog in my project. I then wrote the following code which uses the extension:/// Instantiate an array of `Tweet`s from a property list. /// /// - Parameter url: The URL for a property list made up of one or more `Tweet`s. /// - Returns: Optinal `Tweet` array. If the property list exists, is not malformed, /// and contains all of the key/value pairs required to create one or /// more `Tweet` items, an array of said items will be returned. Othrwise, nil func tweetsWithContentsOfURL(_ url: URL) -&gt; [Tweet] { do { let data = try Data(contentsOf: url) let decoder = PropertyListDecoder() let tweets = try decoder.decode([Tweet].self, from: data) return tweets } catch { OSLog.Error("Failed to load Tweet values from %@ with error: %@", args: String(describing: url), String(describing: error)) return [] } }Here are the arguments being passed into `OSLog.Error`:(lldb) po args ▿ 2 elements - 0 : "file:///var/mobile/Containers/Data/Application/AD339CF3-71DD-4CC3-876B-9668F51ECF2F/Documents/ClientTweets" - 1 : "Error Domain=NSCocoaErrorDomain Code=260 \"The file “ClientTweets” couldn’t be opened because there is no such file.\" UserInfo={NSFilePath=/var/mobile/Containers/Data/Application/AD339CF3-71DD-4CC3-876B-9668F51ECF2F/Documents/ClientTweets, NSUnderlyingError=0x2833b0b70 {Error Domain=NSPOSIXErrorDomain Code=2 \"No such file or directory\"}}" (lldb) po s "Failed to load Tweet values from %@ with error: %@"If the file I'm trying to load is empty, an error is thrown and an error is logged. I'm expecting this under certain test conditions. This code works just fine when running on the simulator. However, when runing on a device, invoking any of the status functions (Debug, Error, or Info) results in "Thread 1: EXC_BAD_ACCESS (code=1, address=0x10)". I check at runtime in the debugger to make sure that `subsystem`, `sessions` and my arguments are all properly initialized and make sense. They look good so I do not understand why this is crashing.What am I missing here?-Michael
Posted Last updated
.