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.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I've been developing a solution that has an embedded USB driver. I can build and run my solution just fine but I cannot pass verification for uploading to App Store Correct and TestFlight
The problem is that the provisioning profile I am using (for development) does not have the explicit Vendor ID (idVendor) but is using the development value of asterisk "*". I've created a release version of my entitlements file with the proper Vendor ID and I have a distribution certificate for iOS. Further, I've created a provisioning profile for app-store distribution (not development) and imported it via Xcode. When I select this provisioning profile, I get the following errors from Xcode:
Xcode 14 and later requires a DriverKit development profile enabled for iOS and macOS. Visit the developer website to create or download a DriverKit profile.
Provisioning profile "MyProvisioningProfile - App Store" doesn't match the entitlements file's value for the com.apple.developer.driverkit.transport.usb entitlement.
If I create and use a DriverKit profile, The Xcode UI errors go away on the "Signing & Capabilities" page. However, these profiles seem to be for development only. I then get an error, during compilation, telling me that the app and extension have two different signers, one for development (DEXT) and one for distribution (App).
To sum up, using a DriverKit profile fails during the build process and using a distribution profile is a non-starter for Xcode. I can't even build.
What do I need to do to get this to work?
Topic:
Code Signing
SubTopic:
Certificates, Identifiers & Profiles
Tags:
Provisioning Profiles
USBDriverKit
TestFlight
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.
I've been studying the AVCam example and notice that everything pertaining to state transitions for the capture session is performed on a dedicated DispatchQueue. My question is this: Can I use an actor instead?
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
Concurrency
Dispatch
AVFoundation
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
}
}
}
}
I've added my Vendor ID to the appropriate entitlement files but my binary fails validation when trying to upload it to the store for distribution. The embeded.mobileprovision file in the generated archive shows an asterisk instead of my approved Vendor ID. How can I make sure the embedded provisioning file has my Vendor ID?
Topic:
Code Signing
SubTopic:
Certificates, Identifiers & Profiles
Tags:
Provisioning Profiles
USBDriverKit
DriverKit