When creating a new Swift Playground / .playgroundbook intended to be used on the iPad App, I often received the error message:
"Problem running playground. There was a problem encountered while running this playground. Check your code for mistakes."
I could track this issue down to be caused when adding certain subviews to my live view. To be more precise, my goal is to split a UIImage into multiple parts and create new UIImageViews for them:
for x in 0..<parts {
for y in 0..<parts {
//Create UIImageView with cropped image
let pieceView = UIImageView.init(frame: CGRect.init(x: CGFloat(x)*singleSize.width, y:CGFloat(y)*singleSize.height, width: singleSize.width, height: singleSize.height))
let imageRef = image.cgImage!.cropping(to: CGRect.init(x:0, y:0, width: 100, height: 100));
pieceView.image = UIImage.init(cgImage: imageRef!)
//Add them to an array
self.viewArray.append(pieceView)
}
}
And that's where things become very tricky for me: Adding 7 of these UIImageViews now works without a problem. But as soon as I want to add 8 or more of them, the playground stops working and gives the error message "Problem running playground..." (see above)
What I tested so far:
Adding UIImageViews with the same image does not cause this problem
Cropping the UIImage in a background thread and adding the view on the main thread does not help either
Creating the UIImageViews without adding them to the live-view does not cause any problems
The code works well when being executed on a mac playground, no matter how man views to add
I experienced this kind of iPad Swift Playground run-time error while adding multiple UI elements.
The problem caused by the default setting of "Enable Results" in the playground's property which is set to be ON. The "Enable Results" previews all the in-line object results' viewer. It makes the swift playground crashed when you produce many UI elements.
Try to disable the "Enable Results". It works for me.
I saw a similar issue, and the problem was that it was just a nil incorrectly used.
In order to get a clear error message, just create a playground with the same files, and run it on the mac: in this way you can get more detailed information about what is going on and find easier to solve your issue.
Let me know if you find any difficulties :)
Probably is a late answer... but I was experiencing same issue during last week... finally today just figure it out how to solve:
I was running a piece of code where I add a background view as next:
func createView(){
// gray background
let marco = CGRect(x:0, y: 0, width: 603, height: 825)
vista = UIView(frame: marco)
vista.backgroundColor = UIColor.gray
vista.isUserInteractionEnabled = true
vista.tag = 5
PlaygroundPage.current.liveView = vista
PlaygroundPage.current.needsIndefiniteExecution = true
}
But I place this at the beginning of the code
What I have changed is :
PlaygroundPage.current.liveView = vista
PlaygroundPage.current.needsIndefiniteExecution = true
Placing it at the end of all the code, before you start to run your program... if you need more detail let me know and can share more information.
Related
I am using a PDFView to display images in my app (built using SwifUI), simply for quick and easy pinch-to-zoom functionality. This worked perfectly in iOS 15, but since updating to iOS 16, the app freezes when attempting to load the image viewer (PhotoDetailView below). The issue persists across both the simulator and a physical device.
Here is the code I'm using:
import SwiftUI
import PDFKit
struct PhotoDetailView: UIViewRepresentable {
let image: UIImage
func makeUIView(context: Context) -> PDFView {
let view = PDFView()
view.document = PDFDocument()
guard let page = PDFPage(image: image) else { return view }
view.document?.insert(page, at: 0)
view.autoScales = true
return view
}
func updateUIView(_ uiView: PDFView, context: Context) {
// empty
}
}
When I run the code on iOS 16.0 in the simulator, I get 2 errors in the console:
[Assert] -[UIScrollView _clampedZoomScale:allowRubberbanding:]: Must be called with non-zero scale
[Unknown process name] CGAffineTransformInvert: singular matrix.
I have been able to isolate the issue to view.autoscales = true. If I print view.scaleFactor, I can see that it is 1.0 before the autoscale and 0.0 afterward (which is what appears to be prompting the errors). These errors also show up in the console when using iOS 15 in the simulator, but the images load as expected.
When view.autoscales = true is commented out, the image loads, albeit at a size that is much larger than the device screen.
Does anyone have any idea what may be causing this? I'd really like to avoid having to build a custom viewer, since I'm just trying to let users quickly pinch to zoom on images.
I managed to resolve this issue. I'm posting my solution here, in case anyone else runs into the same type of problem.
The issue only occurred when using a NavigationLink to navigate to PhotoDetailView. This led me to look more closely at my navigation stack.
After some digging, I found that the problem was related to my use of .navigationViewStyle(.stack) on the NavigationView. I needed this modifier to get things to display correctly on iOS 15, but the same modifier was breaking my image viewer with iOS 16.
My solution was to create a custom container to replace NavigationView, which conditionally uses NavigationStack for iOS 16, or NavigationView + .navigationViewStyle(.stack) for iOS 15. That worked like a charm and my image viewer is back in action.
I found inspiration for my custom container here: https://developer.apple.com/forums/thread/710377
I am currently handling an end-to-end SwiftUI project which involves a ClockKit complication. As one of complication's templates requires an image (UIImage) I need to render (snapshot) an existing SwiftUI View to an image. I have found a couple of possible solutions to this problem, including the following View extension:
extension View {
func snapshot() -> UIImage {
let controller = UIHostingController(rootView: self)
let view = controller.view
let targetSize = controller.view.intrinsicContentSize
view?.bounds = CGRect(origin: .zero, size: targetSize)
view?.backgroundColor = .clear
let renderer = UIGraphicsImageRenderer(size: targetSize)
return renderer.image { _ in
view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
}
}
}
The problem I have is that wherever I implement this extension I keep getting "not in scope" Xcode errors ("Cannot find 'UIHostingController' in scope", "Cannot find 'UIGraphicsImageRenderer' in scope", "Cannot infer contextual base in reference to member 'clear'").
SwiftUI and UIKit are imported in these Swift files (but I think the latter shouldn't be necessary). Xcode 12.5.
Please do share some tips that could help overcome this hurdle... I am a rather inexperienced developer and I could be missing something rather obvious, but at this point I'm pulling my hair out. Whenever I implement a reasonable solution that happened to be in other questions or websites it always comes to UIKit specific commands not being in scope.
Edit: So it turns out this extension works only if implemented in main ContentView for iOS target. Does not work if put in any other directory. However I need this extension to work in files of (watchOS) Extension files (as I said it's needed for CK Complication) and it's not possible to set target membership of the main iOS ContentView also for (watchOS) Extension, as then two ContentViews would apply to one watchOS version and error occurs. How then effectively place the above extension code so it could apply for where it's needed?
The problem for the errors pop up (like Cannot find UIHostingController in scope and others) is because UIHostingController and UIGraphicsImageRenderer are not available on watchOS, meaning the extension, as written, will not compile on that platform.
Refer to my other answered question.
I've been testing around a lot of open-source animated-gif libraries to load GIF files into our Swift project.
Most of them claim to be high-performance libraries, however, whenever I load an animated gif my application uses around 8MB of memory.
The problem is that this dedicated memory space seems to never be released. We can see it growing linearly:
And it makes me wonder if I'm doing the right thing here. Is this behavior correct, or is it potentially bad for the user?
you would need to remove the Gif images manually for them to get cleared from the memory.
Example: gifViwer can be your Gif Viewer in this example
self.gifViewer.removeFromSuperview()
self.gifViewer = nil
if you had to assign a delegate then you can also add
self.gifViewer.Delegate = nil
Note: you need to run this when the viewControler is being completely unloaded as the app will start looking for gifViewer in the view while it has been removed. if you need to clear the gif image from the memory without unloading the view then I suggest to use the steps above and then adding the view to the superView programatically. this is not going to work with the interface designer and IBOutlets
let gifViewer = yourGifViewerClass(frame: CGRect(x: 20, y: 20, width: self.view / 2, height: self.view / 2))
// setup your gifViewer
I am using the following code to add the now playing artwork as a subview in my application.
override func viewDidLoad() {
super.viewDidLoad()
let artWork = musicPlayer.nowPlayingItem?.valueForProperty(MPMediaItemPropertyArtwork)
let image = artWork?.imageWithSize(CGSizeMake(300, 300))
let imageView = UIImageView(image: image)
imageView.frame = CGRectMake(1, 1, 300, 300)
self.view.addSubview(imageView)
}
Not only does the image not appear, I get this warning in the console:
moveCircleAround[2385:753430] BSXPCMessage received error for message: Connection interrupted
Can someone with knowledge in Swift please help me out with this one?
You won't be able to proceed in Xcode 7 beta. All interaction with MPMusicPlayerController is currently broken in iOS 9 beta. Use Xcode 6.4 and iOS 8.4 instead, until this is fixed.
Edit Fixed in beta 5, so it's safe to return to Xcode 7 now.
There are a few cases where this code fails to get the artwork image:
musicPlayer doesn't yet have a nowPlayingItem.
The nowPlayingItem doesn't have an artwork or it's not downloaded yet.
The artwork doesn't find an image of a matching size that you specified.
Try putting a breakpoint at the top of the function and step through the function and see which variable gets set to nil.
Also, note that the BSXPCMessage error could be a hint that the second issue above is the cause. Maybe try a different song and first check that it has an artwork in your Music app.
(Note that you can simplify the code by using nowPlayingItem?.artwork instead of nowPlayingItem?.valueForProperty(MPMediaItemPropertyArtwork).)
With an iOS playground set up as simply as this:
import UIKit
import SpriteKit
import XCPlayground
let s = CGSize(width: 300, height: 300)
let f = CGRect(origin: CGPointZero, size: s)
let view = SKView(frame: f)
let scene = SKScene(size: s)
scene.backgroundColor = SKColor.redColor()
view.presentScene(scene)
XCPShowView("main view", view)
I'm getting this in the console:
2014-09-04 17:02:13.358 SpriteKitBETA7[2009:20695] Error sending deferral props: 0x10000003
There IS a "main view" box in the Assistant Editor thing, but it doesn't display anything. This exact same code (with import Cocoa instead of import UIKit) works perfectly on an OSX playground.
I am aware I can just test stuff in an OSX playground (though it would be more convenient on an iOS one since I don't want to use Yosemite but I do have the iOS7 SDK) and copy-paste to my project, but I wanted to know if anyone understood what's happening here.
Per the Xcode 6 Release Notes, you will want to enable Run in Full Simulator in the File Inspector. Keep in mind this will run kind of slow since it is running through iOS Simulator. You'll have to wait a while for the iOS Simulator to launch before your XCPShowView starts displaying in the playground's Timeline.
In the Xcode menu bar, go to View > Utilities > Show File Inspector (⌘+⌥+1)
In the File Inspector on the right, under Playground Settings, make sure the Platform is set to iOS
Make sure Run in Full Simulator is checked.
If you mouse over the Run in Full Simulator option it explains that you should use this with views that animate or use OpenGL. Both of which apply to using either SceneKit or SpriteKit.
What did you see? I got as far as seeing a scene view with a color background I want. Try this:
import UIKit
import SceneKit
import QuartzCore
import XCPlayground
let view = SCNView(frame: CGRectMake(0, 0, 300, 300))
let myScene = SCNScene()
view.scene = myScene
view.backgroundColor = UIColor.blueColor()
view.backgroundColor = UIColor.yellowColor()
let root = view.scene?.rootNode
XCPShowView("The Scene View", view)
You can test it by diff color, and it rendered it. However, if i add a sphere to the root node, nothing happens. And I also see this in my Console Output:
2014-09-13 16:59:35.766 SceneKitPlayground[23682:13804922] Error sending deferral props: 0x10000003
Additionally, if I switch the thing to OS X, the same code that add the sphere will work.
I managed to get it running by opening the file inspector, changing the playground settings to OSX, then back to iOS and checking 'Run in Full Simulator'. This is in XCode 6.1.