Snapshotting a `UIView` crashes the app with `NSInvalidArgumentException` "[_UIReplicantView _isSymbolImage]: unrecognized selector sent to instance" - swift

Hi guys i have just updated XCode to version 11.4 from the app store and when i try to snapshot a UIView on iOS 13.4 like this:
extension UIView {
func snapshot(at scale: CGFloat) -> UIImage? {
let renderer = UIGraphicsImageRenderer(size: bounds.size)
let image = renderer.image { [weak self] context in
self?.drawHierarchy(in: self?.bounds ?? .zero, afterScreenUpdates: true)
}
return image
}
}
or like that:
extension UIView {
func snapshotOld(at scale: CGFloat) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(bounds.size, false, scale)
guard let currentContext = UIGraphicsGetCurrentContext() else { return nil }
layer.render(in: currentContext)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
and set the resulting image to UIImageView like that:
class ViewController: UIViewController {
#IBOutlet private weak var imageView: UIImageView!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let image = view.snapshot
imageView.image = image
}
}
extension UIView {
#objc var snapshot: UIImage? {
snapshot(at: 3.0)
// snapshotOld(at: 3.0)
}
}
i get:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_UIReplicantView _isSymbolImage]: unrecognized selector sent to instance 0x115907c00'
*** First throw call stack:
(0x1ad52c164 0x1ad240c1c 0x1ad42a7e0 0x1b16a5b6c 0x1ad53085c 0x1ad532b60 0x1b1af6cdc 0x1b1af714c 0x1b1af0b30 0x1025061a8 0x102506270 0x1b1010880 0x1b10112cc 0x1b0f25658 0x1b167fc10 0x1b166f13c 0x1b16a088c 0x1ad4a6c54 0x1ad4a18e4 0x1ad4a1d84 0x1ad4a1660 0x1b78b2604 0x1b167615c 0x102507f78 0x1ad31d1ec)
libc++abi.dylib: terminating with uncaught exception of type NSException
I get this both in simulator and on a real device.
Do you guys have any idea why is this happening? I suspect it is a XCode 11.4 bug because this code worked nicely on the older versions 🤔
Here is a sample project if you would like to try it out on your machine

You're not calling the method you think you are. You have two choices:
Change snapshot to snapshott everywhere (or some other nonambiguous alternative).
Or else, remove the #objc designation.
Do either of those things, and all will be well.

Related

Detect URL Change in ContentView.swift iOS app Swift

Trying to detect change event of the URL being navigated to somewhere else when the user changes the currently viewed webpage. Here is my code.
struct WebView: UIViewRepresentable {
var view = WKWebView()
init() {
print("initialized")
}
func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if let newValue = change?[.newKey] as? Int, let oldValue = change?[.oldKey] as? Int, newValue != oldValue {
//Value Changed
print(change?[.newKey])
}else{
//Value not Changed
print(change?[.oldKey])
}
}
func makeUIView(context: UIViewRepresentableContext<WebView>) -> WKWebView {
while(!authenticated) {
}
DispatchQueue.main.async {
var url = URL(string:"https://www.runixcoin.com/")!
if (faceIdSuccess) {
url = URL(string:"https://www.runixcoin.com/dashboard/auth-login-basic.php?face_id=true")!
}
else {
url = URL(string:"https://www.runixcoin.com/dashboard/auth-login-basic.php?return_url=https://www.runixcoin.com/dashboard/dashboard-4.php")!
}
let request = URLRequest(url: url)
view.load(request)
view.addObserver(view, forKeyPath: "URL", options: .new, context: nil)
}
return view
}
func updateUIView(_ uiView: WKWebView, context: UIViewRepresentableContext<WebView>) {
}
typealias UIViewType = WKWebView
}
The observeValue function is getting called and printing the results I want when the user navigates away from the current page, however the app is crashing... I want to stop the app from crashing. I even tried using the removeObserver code and it either prevented the function from being called or would still crash... What do I need to do?
2022-04-04 18:21:55.489370-0400 Runixcoin[6797:1762100] [error] warning: View context accessed for persistent container runixcoin with no stores loaded
CoreData: warning: View context accessed for persistent container runixcoin with no stores loaded
initialized
Logged in with FaceID
2022-04-04 18:21:58.914721-0400 Runixcoin[6797:1762100] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '<WKWebView: 0x106025e00; frame = (0 0; 428 796); layer = <CALayer: 0x283bb1b80>>: An -observeValueForKeyPath:ofObject:change:context: message was received but not handled.
Key path: URL
Observed object: <WKWebView: 0x106025e00; frame = (0 0; 428 796); layer = <CALayer: 0x283bb1b80>>
Change: {
kind = 1;
new = "https://www.runixcoin.com/dashboard/auth-password-basic.php";
}
Context: 0x0'
*** First throw call stack:
(0x1811e50fc 0x199a35d64 0x182ad0adc 0x1829a30cc 0x18298ed90 0x1829c8508 0x18fd95468 0x18fd951c0 0x18fe1b82c 0x18fe1b380 0x1901932c0 0x18fa41114 0x18fe69850 0x18fa1ebe4 0x18fa1e1f4 0x18d2d6e44 0x18d2d7fb4 0x1812070d0 0x181217d90 0x181152098 0x1811578a4 0x18116b468 0x19cd0f38c 0x183b0e5d0 0x18388cf74 0x188e2a314 0x188d59508 0x188d3acb8 0x104f080d4 0x104f0818c 0x10510daa4)
libc++abi: terminating with uncaught exception of type NSException
dyld4 config: DYLD_LIBRARY_PATH=/usr/lib/system/introspection DYLD_INSERT_LIBRARIES=/Developer/usr/lib/libBacktraceRecording.dylib:/Developer/usr/lib/libMainThreadChecker.dylib:/Developer/Library/PrivateFrameworks/DTDDISupport.framework/libViewDebuggerSupport.dylib
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '<WKWebView: 0x106025e00; frame = (0 0; 428 796); layer = <CALayer: 0x283bb1b80>>: An -observeValueForKeyPath:ofObject:change:context: message was received but not handled.
Key path: URL
Observed object: <WKWebView: 0x106025e00; frame = (0 0; 428 796); layer = <CALayer: 0x283bb1b80>>
Change: {
kind = 1;
new = "https://www.runixcoin.com/dashboard/auth-password-basic.php";
}
Context: 0x0'
terminating with uncaught exception of type NSException
(lldb)

Xcode Swift - WKWebView implementation

I am currently trying to implement a simple WKWebView in a Navigation Page in Xcode using Swift, however, as soon as I switch to the dedicated page the app crashes and throws the following exception:
2021-01-12 16:24:40.981110+0100 SmartMirror[2078:1089320] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[WKWebView view]: unrecognized selector sent to instance 0x11380c400'
I'm also using an activity indicator, which is supposed to show until the page is loaded. This is my code: ThirdViewController.swift
import UIKit
import WebKit
class ThirdViewController: UIViewController, WKUIDelegate {
#IBOutlet var webView: WKWebView!
#IBOutlet var activityIndicator: UIActivityIndicatorView!
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let url = URL(string: "http://192.168.178.34:8080/")
let request = URLRequest(url: url!)
webView.load(request)
webView.addObserver(self, forKeyPath: #keyPath(WKWebView.isLoading), options: .new, context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "loading" {
if webView.isLoading {
activityIndicator.startAnimating()
activityIndicator.isHidden = false
}else {
activityIndicator.stopAnimating()
activityIndicator.isHidden = true
}
}
}
}
And this is my storyboard, with each page having its own view:
https://i.stack.imgur.com/nFFlH.jpg
Help would be greatly appreciated!
Sincerely,
Lukas
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[WKWebView view]: unrecognized selector sent to instance
As you probably know, this is because somebody is sending a -view message to your web view, which doesn't have a method by that name. UIViewController has such a method, though, so it's a good guess that somewhere in your app, your web view is being mistaken for a view controller. I don't see that happening in the code you posted, and it's hard to tell anything from just an image of a storyboard.
The way you can find the issue is to look at the stack trace when the error occurs. Find the thread where the exception is thrown, and then look down the stack for the one where the -view is called. That should show you what method is making the call. If the call isn't in your code, then look at the class involved... you should be able to at least get some clues as to what type of object is calling -view, and you can look at your code for the place where you configure that object.
I have now completely recreated the whole app and it's working now. It seems something went wrong when I created the ViewControllers for the three pages. I have also kept the original ViewController this time.
This is the code I've used after all: ThirdViewController.swift
//
// ThirdViewController.swift
// SmartMirror
//
import UIKit
import WebKit
class ThirdViewController: UIViewController, WKUIDelegate {
#IBOutlet var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let url = URL(string: "http://192.168.178.34:8080/")
let request = URLRequest(url: url!)
webView.load(request)
}
}
Thanks to everyone that helped me!

How to properly copy CAShapeLayer in swift?

I'm trying to create copies of CAShapeLayer in swift but I'm getting a crash
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[CAShapeLayer copyWithZone:]: unrecognized selector sent to instance 0x282e87e60'
which extra steps should I take to allow CALayer .copy() work without crashing the app?
Even if I don't cast the result of .copy() it stills fails exactly at that copy() line...
private var drawLines: [CAShapeLayer]
func getCopiedLayers() -> [CAShapeLayer] {
return drawLines.compactMap { layer -> CAShapeLayer? in
return layer.copy() as? CAShapeLayer
}
}
what I'm doing wrong here?
Thanks in advance for the answers
CALayer does not conform to NSCopying from API, but it conforms to NSSecureCoding, so it is possible to add copying capability as below
Tested with Xcode 11.2 / iOS 13.2 (with CAShapeLayer &
CAGradientLayer)
extension CALayer : NSCopying {
public func copy(with zone: NSZone? = nil) -> Any {
if let data = try? NSKeyedArchiver.archivedData(withRootObject: self, requiringSecureCoding: false) {
if let newInstance = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) {
return newInstance
}
}
fatalError() // << should never got here
}
}
Now, it is possible to call layer.copy() to any layer (theoretically) without exception.

Unable to set the image property of a NSImageView in swift

I'm trying to set a image to an NSImageView but unable to do it.
Here is my code
class zoomableImageView: NSImageView {
var newZoomFactor : CGFloat = 0
// some function ...
}
in the appDelegate class
#IBOutlet var imageView: zoomableImageView!
func applicationDidFinishLaunching(aNotification: NSNotification) {
self.imageView.image = NSImage(named: "Carte.jpg")!
Here is my debug
(lldb) po self.imageView
<imageZoom.zoomableImageView: 0x600000180750>
the imageView is initialized
(lldb) po NSImage(named: "Carte.jpg")
â–¿ Optional(<NSImage 0x600000065b80 Name=Carte Size={376.74418604651163, 282.49833887043189} Reps=("NSBitmapImageRep 0x6000000a6600 Size={376.74418604651163, 282.49833887043189} ColorSpace=(not yet loaded) BPS=8 BPP=(not yet loaded) Pixels=1575x1181 Alpha=NO Planar=NO Format=(not yet loaded) CurrentBacking=nil (faulting) CGImageSource=0x600000162400")>)
the NSImage is created
but
(lldb) po self.imageView.image
nil
The assign is not working
Does some one have any idea ?
Tks for looking
Guillaume
Objects from a NIB file have to wait until awakeFromNib before they are loaded:
override func awakeFromNib() {
self.imageView.image = NSImage(named: "Carte.jpg")!
}

Parse NSInternalInconsistencyException raises with PFImageView

I'm experiencing an odd behaviour of Parse right now.
My App worked fine for weeks of development and never raised a 'NSInternalInconsistencyException' since project setup.
But I just implemented a PFImageView in my ProfileViewController (second VC in UITabBarController, therefore only showing when user is logged in) and my App keeps crashing with this error:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'You have to call setApplicationId:clientKey: on Parse to configure Parse.'
Of course I checked my Parse setup in func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool:
Parse.setApplicationId("myApplicationID", clientKey: "myClientKey")
Parse.enableLocalDatastore()
// This is where I used to activate Parse, but SO and Parse forums kept
// saying you should try to do this at the very beginning
ParseCrashReporting.enable()
PFAnalytics.trackAppOpenedWithLaunchOptionsInBackground(launchOptions, block: nil)
In my ProfileViewController this is where I load my image from Parse:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
userImageView.file = user["profilePicture"] as PFFile
userImageView.loadInBackground { (image, error) -> Void in
if error != nil {
JSSAlertView().danger(self, title: "Loading Image Failed", text: "Please check your connection")
} else {
self.userImageView.image = image
}
}
}
Setting the instance variable of image:
var image: UIImage? {
// If User picked a new image, automatically update imageView
didSet {
userImageView.image = image
// Convert image to PNG and save in in Parse-Cloud
let imageData = UIImagePNGRepresentation(image)
let imageFile = PFFile(name: "profilePicture.png", data: imageData)
// Attach this file to our user
user["profilePicture"] = imageFile
user.saveInBackgroundWithBlock { (success, error) -> Void in
if error != nil {
JSSAlertView().danger(self, title: "Failed To Save Image", text: "Please try again saving your image!")
}
}
userImageView.file = user["profilePicture"] as PFFile
}
}
I have no clue what kind of connection could be between these things, but I didn't change anything else in the whole project.
Regards,
Ok, finally after hours of trial and error I found the solution for this problem.
You should never ever execute parse calls in the header of view controllers, as these calls could be executed before the API registration.
For example:
class ViewController: UIViewController {
// this will crash the app as above!
var user: PFUser! = PFUser.currentUser()
override func viewDidLoad() {
super.viewDidLoad()
// initialize the user here. This will work just fine
user = PFUser.currentUser()
}
}
Hope this saves you from having the same errors!