Post

Replies

Boosts

Views

Activity

Reply to perspectiveTransform causing large memory spike / app being killed
I understand where you are coming from, but also the notion of georeferencing maps and images is pretty standard in these specific categories of apps. I'm already doing it with KML Image Overlays, and other than the need to rotate / skew the image the data itself isn't the problem - it's the bitmap representation from mapping the geocoordinates to the map and then needing to map that to the scale of the image. In other words, if the PDF is north-up already, it overlays perfectly. It's when we need to skew it / manipulate the image we have the issue. The GDAL/PDF libraries are outside of the scope of this really - I've already processed the PDF / TIFF and extracted the geocoordinates at this stage. But I've custom compiled GDAL with Proj and PDFium, though we've done the coordinate testing with Poppler as well and gotten the same results.
Topic: UI Frameworks SubTopic: General Tags:
Sep ’25
Reply to perspectiveTransform causing large memory spike / app being killed
Just to make it a little clearer, here's a (cleaned up) version of my renderer. If I skip lines 26 to 36 (the transform filter) this renders in the bounding box size wise. But if I keep those lines in, I get the out of memory exception. This unfortunately isn't just a simple rotation, because, well, 2D box on a 3D Earth. But hopefully that helps explain a little more what's going on. class PDFOverlayRenderer: MKOverlayRenderer { override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) { var boundingRect = self.rect(for: overlay.boundingMapRect) guard let cgDocument = CGPDFDocument(overlay.pdfUrl as CFURL), let cgPage = cgDocument.page(at: 1) else { return } let pdfPageRect = cgPage.getBoxRect(.mediaBox) let renderer = UIGraphicsImageRenderer(size: pdfPageRect.size) img = renderer.image { ctx in UIColor.white.set() ctx.fill(pdfPageRect) ctx.cgContext.translateBy(x: 0.0, y: pdfPageRect.size.height) ctx.cgContext.scaleBy(x: 1.0, y: -1.0) ctx.cgContext.drawPDFPage(cgPage) } var img: UIImage! UIGraphicsPushContext(context) if !overlay.actualCoords.isEmpty { var ll = self.point(for: overlay.actualCoords[3]) var lr = self.point(for: overlay.actualCoords[2]) var ur = self.point(for: overlay.actualCoords[1]) var ul = self.point(for: overlay.actualCoords[0]) let ciImg = CIImage(image: img)! let perspectiveTransformFilter = CIFilter.perspectiveTransform() perspectiveTransformFilter.inputImage = ciImg perspectiveTransformFilter.topRight = cartesianForPoint(point: ur, extent: boundingRect) perspectiveTransformFilter.topLeft = cartesianForPoint(point: ul, extent: boundingRect) perspectiveTransformFilter.bottomRight = cartesianForPoint(point: lr, extent: boundingRect) perspectiveTransformFilter.bottomLeft = cartesianForPoint(point: ll, extent: boundingRect) let txImg = perspectiveTransformFilter.outputImage! img = UIImage(ciImage: txImg) boundingRect.origin = CGPoint(x: minX, y: minY) } img.draw(in: boundingRect, blendMode: .normal, alpha: 1.0) UIGraphicsPopContext() } func cartesianForPoint(point:CGPoint, extent:CGRect) -> CGPoint { return CGPoint(x: point.x,y: extent.height - point.y) } }
Topic: UI Frameworks SubTopic: General Tags:
Sep ’25
Reply to perspectiveTransform causing large memory spike / app being killed
Thanks. It is geospatial PDF, and I've already incorporated GDAL to extract the coordinates, so that's not the issue. Basically the issue is - when I use the drawPDFPage it properly fills the bounding rectangle. However, I need to also apply a perspectiveTransform and when I go to draw that it runs out of memory. So somehow the scaling logic is just fine if I don't transform it - I'm trying to figure out how to transform it but still have it be able to draw appropriately without running out of memory
Topic: UI Frameworks SubTopic: General Tags:
Sep ’25
Reply to Crash in libswiftCore with swift::RefCounts
(For posterity and web searches) One can create a serial queue by using the default initializer for DispatchQueue: private let serialQueue = DispatchQueue(label: "some.custom.label") I'm then initializing the Connection Group like: connectionGroup = NWConnectionGroup(with: multicastGroup!, using: params) and finally starting it with: connectionGroup.start(queue: serialQueue) It's that last line that's super important because the default global() queue will give you a concurrent queue rather than a serial one.
Topic: Programming Languages SubTopic: Swift Tags:
Jul ’25
Reply to Crash in libswiftCore with swift::RefCounts
Ah yes, great point! I think that's exactly what it was. I had fixed the issue initially by processing in a serial queue, but your comment made me go back and realize the connection group was getting started like this: connectionGroup.start(queue: .global()) Which is, of course, a concurrent queue. With the serial queue in place I was able to flood the device with thousands of UDP messages without issue. Thanks so much!
Topic: Programming Languages SubTopic: Swift Tags:
Jul ’25
Reply to Crash in libswiftCore with swift::RefCounts
2025-06-09_18-48-03.1721_-0600-43bc27c538c2f93348a83e5380b5f016cc859f71.crash Thanks Quinn! I'm attaching one of the crash logs here. However your pointer got me to the issue - it's a race condition when the device is getting lots of messages over UDP from lots of other disparate devices and those messages are getting split over multiple packets. The completion handler is spinning up a new thread, but working off of the same instance of an underlying class which is where I think the issue is. I was able to replicate it by flooding the device with a bunch of partial messages randomly and could easily reproduce.
Topic: Programming Languages SubTopic: Swift Tags:
Jul ’25
Reply to Certificate exceeds maximum temporal validity period
FWIW, if I do this I work around I can get it to pass, but I don't like it mainly because I don't know what other exceptions might be caught up in this if error != nil && error.debugDescription.contains("not standards compliant") { let errDataRef = SecTrustCopyExceptions(secTrust) SecTrustSetExceptions(secTrust, errDataRef) isValidCertificate = SecTrustEvaluateWithError(secTrust, &error) }
Topic: Privacy & Security SubTopic: General Tags:
Dec ’24
Reply to Certificate exceeds maximum temporal validity period
@DTS Engineer We're starting to run into this more and more as we're getting clients using root certs from after the 2020 cut-off date. What I'm baffled by is that in the Darwin code there's this: Don't check validity periods against maximums for user-anchored leafs In the above code I've got the certificates I want to trust, which are for all intents and purposes self-signed certificates. Do I need to flag somehow that these aren't the system root certificates for this to work?
Topic: Privacy & Security SubTopic: General Tags:
Dec ’24
Reply to Certificate exceeds maximum temporal validity period
Here's the full code block where we're validating the certificates. Effectively we're given the certificate chain and we attempt initially to validate without it against the standard installed certs, and then add the custom ones and try again (ignoring hostname for custom certs). It's in the second verification that it's failing solely because of the temporal validity issue: sec_protocol_options_set_verify_block(securityOptions, { (_, trust, completionHandler) in self.logger.debug("Entering Verify Block") let secTrust = sec_trust_copy_ref(trust).takeRetainedValue() isValidCertificate = SecTrustEvaluateWithError(secTrust, &error) if !isValidCertificate { self.logger.debug("Server not trusted with default certs, seeing if we have custom ones") var customCerts: [SecCertificate] = [] let trustCerts = SettingsStore.global.serverCertificateTruststore self.logger.debug("Truststore contains \(trustCerts.count) cert(s)") if !trustCerts.isEmpty { self.logger.debug("Trusting Trust Store Certs") trustCerts.forEach { cert in if let convertedCert = SecCertificateCreateWithData(nil, cert as CFData) { customCerts.append(convertedCert) } } } if !customCerts.isEmpty { // Disable hostname validation if using custom certs let sslWithoutHostnamePolicy = SecPolicyCreateSSL(true, nil) SecTrustSetPolicies(secTrust, [sslWithoutHostnamePolicy] as CFArray) SecTrustSetAnchorCertificates(secTrust, customCerts as CFArray) } // Make sure we still trust our normal root certificates SecTrustSetAnchorCertificatesOnly(secTrust, false) // Try again isValidCertificate = SecTrustEvaluateWithError(secTrust, &error) if let error { self.logger.error("SecTrustEvaluate failed with error: \(error)") } } completionHandler(isValidCertificate) }, .global())
Topic: Privacy & Security SubTopic: General Tags:
Oct ’24
Reply to Certificate exceeds maximum temporal validity period
Thanks as always Quinn! In running Console I don't see any specific messages about leaf validity period, only these two messages. I have opened a support request already that has the domain we're attaching to when experiencing the issue if that's helpful. As far as we can tell these certificates meet all of the requirements from that article - for example, it's only trusted for 394 days, not expired, etc. These aren't self-signed, but root-trusted certificates. Happy to dig in more if there's something else I can provide!
Topic: Privacy & Security SubTopic: General Tags:
Oct ’24
Reply to Certificate exceeds maximum temporal validity period
So I'm reminded I could inspect the CFError and set individual policies, for example we ignore Hostname policies when using custom certificates: let sslWithoutHostnamePolicy = SecPolicyCreateSSL(true, nil) SecTrustSetPolicies(secTrust, [sslWithoutHostnamePolicy] as CFArray) SecTrustSetAnchorCertificates(secTrust, customCerts as CFArray) SecTrustSetAnchorCertificatesOnly(secTrust, false) So if there's a policy we could use for validity to disable that check, I'm definitely OK with that as a workaround.
Topic: Privacy & Security SubTopic: General Tags:
Oct ’24