Random image generator causing memory issues - memory-management

I have a random image generator within an app, however after 5/6 images have been shown in an image view, the apps memory usage is very high causing the didReceiveMemoryWarning() to run. However when the button is pressed quickly the app crashes.
At the start of the app
After 5 or 6 images have been generated
After didReceiveMemoryWarning() has been called
The code that creates the images is
#IBAction func RandomImage(_ sender: Any) {
let randomIndex = Int(arc4random_uniform(UInt32(56)))
imageView.image = UIImage(named: "image\(randomIndex)")
}
with the average image size being shown 600kb.
Is there a way to use or clear the memory more efficiently? Or am I miss using the UIimageView? Would it be best practise to load the image from a data object?

Related

Anchor detection issues in AR application

I have an augmented reality app with a simple Reality Composer project.
It works fine on an ipad 14.4 but I'm having problems on higher versions (14.7 and 15).
Anchor detection is much more sensitive. This has the consequence of restarting my scenes with each new image detection.
On the other hand, the scenes are interrupted as soon as the image of the anchor is no longer visible by the camera.
I am using xcode 13.1
I use this simple code :
import RealityKit
class ViewController: UIViewController {
#IBOutlet var arView: ARView!
override func viewDidLoad() {
super.viewDidLoad()
guard let anchor2 = try? Enigme1.loadDebut() else { return }
arView.scene.anchors.append(anchor2)
}
}
Thank you very much for the help you could give me.
The behavior style of Reality Composer's and RealityKit's AnchorEntity(.image) is the same as ARKit's anchor in ARImageTrackingConfiguration – if a tracked image is no longer visible in a view, there will be no ARImageAnchor, thus, there will be no 3D model.
When using AnchorEntity(.image), if your 3D model has more than 100,000+ polygons, every time it reappears on the screen it will cause a slight freeze.

Resizing image to fit Ui Image View in xcode storyboard

I am trying to fit an image to fit the entire of the Ui Image View. I want to do this because I want to round my image and it does not work because the image is smaller than the entire view. So rounding it rounds the outside of the image and is not visible. I have tried to add constraints but that does not seem to have workout.
Here is an image of what I am trying to do:
https://i.stack.imgur.com/mIGow.png
The problem images:
https://i.stack.imgur.com/LGDyx.png
https://i.stack.imgur.com/K3RVZ.png
OK - the problem is that you don't understand the Xcode interface.
When you have added a UIImageView, set its image, and then select it, you see this:
If you click the image view again, Xcode shows an additional "highlight" outline:
That has nothing to do with how it will look when you run your app.
Regarding the screen-cap from the video you are watching... You either didn't notice, or forgot, two things:
it's a tutorial for SwiftUI - the screen-caps you've posted for what you're trying to do is from a UIKit based app.
at 17:20 of Part 1 of that series, the author explains how he is setting the corner radius.
To get what you want with UIKit, you need to write some code to give the image view rounded corners. To have it show up at design-time, you need to use an #IBDesignable image view subclass.
Here's a very basic example:
#IBDesignable
class RoundedImageView: UIImageView {
override func layoutSubviews() {
layer.cornerRadius = 20
}
}
If you set the Custom Class of your image view to RoundedImageView, and then either select either Editor -> Refresh All Views or have Editor -> Automatically Refresh Designable Views checked, you'll see this:

Scaling NSTextAttachment in NSPasteboard

I have an NSTextAttachment which contains an NSImage. What I would like to do is scale this image so that it's smaller in dimensions but will keeping the same number of pixels. Then moving it to the general pasteboard. Once it's pasted (into whatever app) I would like it to paste with the same dimensions I just set. The problem I am having is that pasting it in any other app always puts it at is original dimensions. I have tried the following things and none seem to fully work
First is simply resizing the image and then copying. This retains the proper dimensions (let's say 100 x 100 pt) but the image is very blurry and the resolution is 72 dpi.
//variable im is an NSImage object that is present
//variable newsize is an NSSize which is calculated to give the image proper resolution
im.lockFocus()
im.size = newsize
im.unlockFocus()
The second thing I have tried is use the techniques listed on this page. None of which do anything once I paste the TextAttachment to another app (such as Pages for example). Subclassing NSTextAttachment has no effect. Also changing the bounds of the attachment seems to have no effect once it's pasted.
The last thing I tried is after the iterating through the NSAttributedString which holds the attachments, and setting each one's bounds. Still no effect when pasting into other apps.
So the ultimate question: is there a way to have a scaled NSImage inside and NSTextAttachment copy to the clipboard?
func copy() {
let pboard = NSPasteboard.general()
pboard.clearContents()
let rtf = NSMutableAttributedString()
//self.images is an array that contains a bunch of images
//note that it is required that I use a RTF to copy/paste my images
//because there is text mixed with the images
//for simplicity I have removed the text from this code
//removing it from my app and doing the same code has no effect
for im in self.images {
let a = NSTextAttachment() //subclassing NSTextAttachment has no effect on pasted image size
a.image = im
a.bounds = NSMakeRect(0,0,100,100) //has no effect on pasted image size
//if I resize the image prior to copying (using the code above)
//the pasted image has correct dimensions but is very blurry.
let str = NSAttributedString(attachment: a)
rtf.append(str)
}
pboard.writeObjects([rtf])
}

SpriteKit unarchiveFromFile does not load textures from asset catalogues and atlases

I'm still new with SpriteKit, and wanted to see if I can construct a level using Xcode's SKS editor. When i added a couple of sprites with the "Spaceship.png" texture and built the template app, the textures don't load.
Here's a screenshot of the vanilla OSX Game template using Swift as the language, and adding a supplied "Spaceship.png" sprite. The texture shows fine:
And here's the result of building and running the app with only that modification to the template:
The debug console displays this warning message:
I tried to add an .atlas folder, and got the same result. the scene just displays the red X icon in place of the sprite. If the added sprites where just color sprites, they display fine. I had an app some time ago that I scrapped, where I used to load the SKScene and would manually add the sprite assets within to my SKScene sub-class, and it worked fine.
If, however, i moved the textures - "Spaceship.png" as an example - to the root of the project, i.e. not inside an asset catalogue or .atlas folder, the scene loads with the textures displaying fine.
Here's the texture added to the root of the project:
And this is the desired result:
I tried to manually add the loaded assets from the SKS file to the scene via enumerateChildNodesWithName(_,usingBlock) and I get the same result if the textures were not in the root of the project folder.
This is me trying to add the assets manually:
func applicationDidFinishLaunching(aNotification: NSNotification) {
/* Pick a size for the scene */
if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
let sceneToBePresented = GameScene()
/* Set the scale mode to scale to fit the window */
sceneToBePresented.scaleMode = .AspectFill
sceneToBePresented.size = scene.size
/* Sprite Kit applies additional optimizations to improve rendering performance */
self.skView!.ignoresSiblingOrder = true
self.skView!.showsFPS = true
self.skView!.showsNodeCount = true
scene.enumerateChildNodesWithName("*") { node, stop in
sceneToBePresented.addChild(node.copy() as SKSpriteNode)
}
self.skView!.presentScene(sceneToBePresented)
}
}
I looked around SpriteKit classes - SKNode, SKScene, SKTexture, SKSPriteNode - for any clue about paths, caching, preloading, or anything but was unable to find a thing that could make this work.
I am running Xcode 6.1.1 and my target is 10.9, and the language I'm using is Swift, although the same behavior holds true using ObjC. Is this a feature or a bug? Anybody else running/ran into a similar situation ?
Thanks in advance for any help
[UPDATE]
Looks like this is not implemented yet - loading textures from asset catalogs - as this post in the dev forums discusses the same issue, and his solution is to rename the asset catalogues to be the same name as the texture. In essence, what I found out about having the image files in the root folder: How do you load sprite textures from Images.xcassets when using SKS scene file, although my earlier app which i managed to roll-back to a working state does load textures from .atlas'es, but i can't seem to do it with a clean template!!!
[Answering my own question here]
As far as I can tell, at this moment, loading texture from asset catalogues - Images.xcassets - while unarchiving or deserializing an SKScene file does not work on OSX based on my attempts and the devforumns post referenced above.
Loading of the textures from image atlases, however, works by forcing SKTexture to load the image. Forcing or 'touch'ing SKTexture can be done via the preloadWithCompletionHandler(_:) or preloadTextures(_:, withCompletionHandler:) methods, or simply by printing the description of the sprite's SKTexture as i have discovered.
For the benefit of anybody who might need further assistance, here is a code snippet that preloads the textures after unarchiving an SKS file:
if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
for child in scene.children as [SKNode] {
if child is SKSpriteNode {
let sprite = child as SKSpriteNode
sprite.texture?.preloadWithCompletionHandler({ })
/* or even a simple debug log of the texture */
/* println(sprite.texture) */
}
}
/* Do your other stuff ... */
...
}
If I'm wrong please correct me. Until somebody does, or Apple fixes the discrepancy between SpriteKit's behavior between iOS and OSX, I will not be looking for another solution, and will follow Murphey's law:
If it works, don't fix it
Follow Salam Horani solution's, for Swift 2.x you dont have yet "unarchiveFromFile" so you can create scene like this:
if let gameScene = GameScene(fileNamed: "GameScene") {
// ...
}

UICollectionView scroll lag

I have setup a collection view with 10 subviews in a cell.
The subviews are
-imageview with label on it
-text view
-imageview
-uilabel
-imageview
-uilabel
Initially the collection view have 15 cells displayed at the time on an iPad. No when I scroll the scroll pauses when it is time to replace the cells at the bottom or top(reusing cells). I removed the shadow but still the same issue.
So the problem happens when the old cell is reused causing a lag.
Btw, no images loaded via the network.
I had the answer to this long time ago but for the benefit of others and who may be in the same issue.
Apart from removing shadows, you also need to remove "clear color" backgrounds. Any additional drawing that will require additional processing should be removed or replaced with an alternative. Any heavy lifting, text formatting, date formatting should be done before even showing the collection or table views. Make sure you cell only does the presenting and not processing. If you can't avoid it do the processing at another thread.
To measure the rate of the scroll you will need to use the instruments > graphics > core animation tool to measure the frame rate.
Try it and you will notice a difference.
EDIT: No need to experiment with autoresizing masks, just read this short article about UICollectionView performance boost http://noxytrux.github.io/blog/2014/09/25/ios8-weirdness-part3-laggy-uicollectionview/
It is probably an autolayout overhead. Consider trying autoresizing masks instead.
You can just commit everything and make an experiment:
turn off autolayout on your cell xib file
run an app to test performance (don't worry about messed up layout)
setup autoresizing masks (and do layout in code if needed) instead of autolayout if the effect is noticeable
I fixed my UICollectionView performance problems this way. It helps most when you have a lot of visible cells at a time.
Also, if you have image views, please see this answer Setting image property of UIImageView causes major lag
Don't forget about Instruments: run Time Profiler and see what eats your main thread time most.
I guess the issue can be also because of ImageView.
Using Kingfisher 5 for prefetching, loading, showing and caching images will solve the issue.
let url = URL(fileURLWithPath: path)
let provider = LocalFileImageDataProvider(fileURL: url)
imageView.kf.setImage(with: provider)
https://github.com/onevcat/Kingfisher/wiki/Cheat-Sheet#image-from-local-file
fileprivate func downloadForPerformance()->void{
for i in urlToFetchImageArray {
var image: UIImage = dowloadImageFunc(link: i.urlString() );
imageArray.append( image );
}
}
fileprivate func dowloadImageFunc(link: String)->UIImage {
let url = URL(string: link)
let data = try? Data(contentsOf: url!)
return UIImage(data: data!) ?? UIImage(named: "default.png")!;
}
cell?.mainImage.image = self.imageArrayPerformance[indexPath.row];
Usually the problem is slow download as each cell is dequeue.
Call downloadForPerformance func before the view has appeared.
This will fill an array called imageArray as a global variable
Then use that array in cellForItem func
basically have an array of already downloaded images you will need, make this a [UIImage] array, then use theImageArray[indexPath.row]

Resources