SwiftUI macOS view starts lagging when displaying multiple charts
I am displaying multiple charts in a view.
The charts are just paths in a frame and data comes from an csv file (not bigger than 400mb).
Those charts are displayed inside of a LazyVGrid and the whole view is inside a scroll view.
Loading the view takes about 10 - 20 seconds, but when I start scrolling through the charts, it becomes very laggy.
To solve this I tried to attach .drawingGroup() to the chart views, but there where nearly no performance change.
the code looks something like this:
import SwiftUI
struct GroupView: View {
@State var chartData = [CGFloat]()
let columns = [
GridItem(.adaptive(minimum: 720))
]
var body: some View {
VStack{
ScrollView {
LazyVGrid(columns: columns){
CSVChart(data: chartData, chartName: String, x-yaxisName: [String](), lineColor: CGColor)
.frame(width: 700, height: 300, alignment: .center)
.drawingGroup() // there is as well no performance change when .drawingGroup() is inside the chart view
}
}
}.onAppear{
chartData = // get csv data logic
}
}
}
I know that the csv file is quite large, and that this will cause the slow behaviour, but I thought that other apps aren't that laggy when working with large files so this might be fixable.
It would be great if someone could help me with this problem.
See also questions close to this topic
-
Modular development in iOS
How do I add a module and manage their dependency in Xcode using swift?
Is there a way like I could done it by a few clicks in Android Studio?
What exactly is the keyword I should search for?
Or should I even need to do this in iOS development?
-
There is more than one bundle with the CFBundleIdentifier value 'org.alamofire.Alamofire' under the iOS application
I recently updated a project to Xcode 12 and I had to update carthage to 0.37. When I did that, build was fine but when I tried to push the app to the testflight, I got this error:
ERROR ITMS-90685: "CFBundleIdentifier Collision. There is more than one bundle with the CFBundleIdentifier value 'org.alamofire.Alamofire' under the iOS application '
This issue happens because I do not know how to set the frameworks come from carthage "Do not embed". In the carthage docs, they say that remove the copy-frameworks script and there is no alternative or a new way to copy frameworks as I see. How can I copy the xcframeworks without embedding in Xcode?
-
Trouble With UIViewAnimation
I'm getting in trouble on UIView Animation. When I click into one of UITextFields basically everything works fine until I select another UITextField after being selected the other one, the fields move up and down then return to the same place after I select the other UITextField.
What am I doing wrong? What I expected is to move the whole UIStackView containing my fields into up to avoid the keyboard to cover it all. Also, to keep the animation static when I click into the other UITextField, just returning to the default position when the keyboard got dismissed.
class LoginViewController: UIViewController { var coordinator: MainCoordinator? override func viewDidLoad() { super.viewDidLoad() viewTapped() setupScreen() setupViews() setConstraints() } private func setupScreen() { self.view.backgroundColor = .systemPink } private func setConstraints() { self.textFieldLogin.heightAnchor.constraint(equalToConstant: 50).isActive = true self.textFieldLogin.widthAnchor.constraint(equalToConstant: 190).isActive = true // self.textFieldSenha.heightAnchor.constraint(equalToConstant: 50).isActive = true self.textFieldSenha.widthAnchor.constraint(equalToConstant: 190).isActive = true // self.loginButton.widthAnchor.constraint(equalToConstant: 145).isActive = true self.loginButton.heightAnchor.constraint(equalToConstant: 50).isActive = true // self.stackView.heightAnchor.constraint(equalToConstant: 200).isActive = true self.stackView.widthAnchor.constraint(equalToConstant: 200).isActive = true self.stackView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true self.stackView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true } private func setupViews() { self.view.addSubview(self.stackView) self.viewTapped() } private lazy var textFieldLogin: UITextField = { let textFieldLogin = UITextField() textFieldLogin.tag = 1 textFieldLogin.translatesAutoresizingMaskIntoConstraints = false textFieldLogin.layer.cornerRadius = 3.7 textFieldLogin.textAlignment = .center textFieldLogin.placeholder = "Usuário" textFieldLogin.backgroundColor = .white textFieldLogin.delegate = self return textFieldLogin }() private lazy var textFieldSenha: UITextField = { let textFieldSenha = UITextField() textFieldSenha.tag = 2 textFieldSenha.translatesAutoresizingMaskIntoConstraints = false textFieldSenha.layer.cornerRadius = 3.7 textFieldSenha.textAlignment = .center textFieldSenha.placeholder = "Senha" textFieldSenha.backgroundColor = .white textFieldSenha.delegate = self return textFieldSenha }() private lazy var loginButton: UIButton = { let loginButton = UIButton() loginButton.translatesAutoresizingMaskIntoConstraints = false loginButton.layer.cornerRadius = 3.8 loginButton.titleLabel?.font = UIFont(name: "Arial", size: 19) loginButton.setTitle("Entrar", for: .normal) loginButton.setTitleColor(.systemGreen, for: .normal) loginButton.backgroundColor = .white return loginButton }() private lazy var stackView: UIStackView = { let stackView = UIStackView(arrangedSubviews: [self.textFieldLogin, self.textFieldSenha, self.loginButton]) stackView.translatesAutoresizingMaskIntoConstraints = false stackView.backgroundColor = .systemBlue stackView.axis = .vertical stackView.distribution = .equalSpacing return stackView }() private func viewTapped() { let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap)) self.view.addGestureRecognizer(tapGesture) } @objc func handleTap(sender: UITapGestureRecognizer) { UIView.animate(withDuration: 1.1, delay: 0, usingSpringWithDamping: 5.1, initialSpringVelocity: 5.0, options: .curveEaseIn, animations: { self.stackView.frame.origin.y = self.stackView.frame.origin.y + 130 self.textFieldLogin.resignFirstResponder() self.textFieldSenha.resignFirstResponder() }, completion: nil) } } extension LoginViewController: UITextFieldDelegate { func textFieldDidBeginEditing(_ textField: UITextField) { UIView.animate(withDuration: 1.1, delay: 0, usingSpringWithDamping: 5.1, initialSpringVelocity: 5.0, options: .curveEaseIn, animations: { self.stackView.frame.origin.y = self.stackView.frame.origin.y - 130 }, completion: nil) } func textFieldDidEndEditing(_ textField: UITextField) { UIView.animate(withDuration: 1.1, delay: 0, usingSpringWithDamping: 5.1, initialSpringVelocity: 5.0, options: .curveEaseIn, animations: { self.stackView.frame.origin.y = self.stackView.frame.origin.y + 130 }, completion: nil) } func textFieldShouldReturn(_ textField: UITextField) -> Bool { textField.resignFirstResponder() return true } }
-
"RuntimeError: invalid slot offset" on trying to run python package
I use the
pyhyphen
package for a script I run all the time. Recently, I updated to MacOS Big Sur. Spyder was laggy, but I fixed that by running a virtual environment andpip install
ing what I needed. No issues.Now, when I try to run
from hyphen import Hyphenator
(here is the package page), I get the following error:runcell(0, '/Users/myname/Documents/project/project.py') Traceback (most recent call last): File "/Users/myname/Documents/project/project.py", line 17, in <module> from hyphen import Hyphenator File "/Users/myname/anaconda3/lib/python3.8/site-packages/hyphen/__init__.py", line 10, in <module> from .hyphenator import Hyphenator File "/Users/myname/anaconda3/lib/python3.8/site-packages/hyphen/hyphenator.py", line 27, in <module> from . import hnj RuntimeError: invalid slot offset
The
from hyphen import Hyphenator
is the only line in the script. I've tried uninstalling/reinstalling the package six hundred times - and I cannot find any kind of solution forinvalid slot offset
. All other packages import fine, no issues.Spyder (in Anaconda) is running python version 3.8.5. I have non-anaconda 3.9 installed, but I can't imagine that has any effect since I'm running spyder in a virtual environment.
-
(Linux/Mac) find command - how to execute multiple commands to the same file before moving on to the next one?
Edit: My shell version is requested:
zsh 5.7.1 (x86_64-apple-darwin18.2.0)
I'm on Mac, but this is a Linux command (
find
) I'm using in terminal.So my overall goal is already somewhat reached, but I'm wanting to make it cleaner/more efficient and have less problems.
I'm converting a bunch of .wav and .aif files in several sorted directories to .flac using:
find . -type f -name "*.aiff" -exec flac -8 "{}" \; && find . -type f -name "*.aiff" -exec rm "{}" \; && find . -type f -name "*.wav" -exec flac -8 "{}" \; && find . -type f -name "*.wav" -exec rm "{}" \;
(convert.sh)Which works, if I'm not continuing work in the directory. Doing so produces more .wav and .aif files that end up being deleted without being converted since I produce them during conversion, and
find
isn't looking for more wavs to convert after the first part of code is executed, only for wavs to delete.I've tried using && with
find
- for example:find . -type f -name "*.wav" -exec flac -8 "{}" && rm "{}" \;
However that seems to think after && is a new command, not part of the same command I want to execute, and gives errorfind: -exec: no terminating ";" or "+"
.(Potential Solution) I know I could somehow use a .sh file but I don't know how to set it up so that it works like
/path/to/convertanddeletebeforenextfile.sh /path/to/filetoconvert.wav
to be able to usefind . -type f -name "*.wav" -exec /path/to/convertanddeletebeforenextfile.sh "{}" \;
Could someone help me with this final straight to the point goal:
Convert .wav/.aif to .flac and delete original, then move to next .wav/.aif
-
How to add own images in customized ribbon in outlook?
Outlook->File->Options->Customize Ribbon In customize ribbon their is customize tab. In that tab different sab-tabs then how can we add images to that sub-tabs. We can say how can we add own images to them like icon images.
-
Pandas getting values splitted in variables
So, I'm trying to use pandas to go through a CSV line by line and split the value of every column into variables.
csv = pandas.read_csv('file.csv', sep = ';', usecols = ['ref', 'design', 'quant'])
I need to get the ref, design and quant values into 3 separated variables so I can process it, after that go to the next line.
Thanks for the help!
-
Python and csv reader: Failing to print all the rows in a text file that do NOT have a field that contains a certain string
I have the following repl.it program, and cannot get one part of the program to work (the logic is wrong)
The context is that of a dating site. in the "matchmagic" subroutine, I want to be able to retrieve all rows in the database that do NOT have the keystrength variable.
In other words, if a user types in "patience", then every row in the text file that DOES NOT contain that word, is displayed (i.e all the users that are not patient) as we are going for contrasting personalities for a match.
The whole program is here:
https://repl.it/@oiuwdeoiuas/Matchmakingskills-1
The relevant part of the program is:
def matchmagic(): wordfound=False print("===Creating Match===") while wordfound==False: with open("dating.txt","r") as f: keystrength=input("Enter one of your key strengths:") reader=csv.reader(f) for row in reader: for field in row: if field != keystrength: print(row) wordfound=True search() mainmenu()
What I have tried here is obvious, but I think there is an issue with the following:
if field != keystrength: print(row) wordfound=True
It prints all the rows instead of identifying the rows that do not contain that identified keystrength.
Sample CSV:
Joe,Bloggs,JoeBbird,open123,M,jblogs@gmail.com,10/10/20,Christian,patience,0
FName,LName,Username,password,Gender,email,dob,Religion,keystrength,contactcount
In the example above, if this user is logged in, their keystrength is "patience", and the program should return all the rows (usernames or first and last names) of users that do NOT have "patience" listed anywhere in their files.
-
Python, repl.it - details are not being written to file using csv.writer and writer.writerow
I have the following repl.it program, and note that the registration part of the program, that was working fine before, has stopped working.
It gets to the end where it says "written to file" but somehow the actual write-rows command is being skipped as nothing is written to the text file.
The whole program is here:
https://repl.it/@oiuwdeoiuas/Matchmakingskills-1
The relevant part of the code is below, although there may be other factors (hence whole code provided)
def register(): print("===Register====") print("First things first, sign up and tell us a little about yourself") with open("dating.txt","a") as fo: writer=csv.writer(fo) firstname=input("Enter first name:") lastname=input("Enter last name:") username=firstname+lastname[0]+"bird" print("Your automatically generated username is:",username) password=input("Enter password:") gender=input("Enter gender") email=input("Enter email:") dob=input("Enter date of birth in format dd/mm/yy:") beliefs=input("Enter beliefs") strengthslist=["patience","efficiency","sensitivity","frankness","submissiveness","leadership","timekeeping","laidback"] print(strengthslist) strengths=input("Enter your top strength: (select from the above list)") contactcount=0 writer.writerow([username,password,firstname,lastname,gender,email,dob,beliefs,strengths,contactcount]) print("written to file") mainmenu()
-
SwiftUI iMessage / WhatsApp style text input
I've seen so many articles on this I've lost my mind. I'm trying to do a really simple thing but it seems so hard.
I'm trying to achieve something like this
https://objectpartners.com/2019/07/09/building-an-ios-chat-feature-without-hacks/
Basically when you click the text input it shows keyboard and when you scroll the chat down (ScrollView) it hides the keyboard.
First of all I want this smooth interactive scroll to hide / show the text input with keyboard:
UIScrollView.appearance().keyboardDismissMode = .interactive
This is working good except one problem. It's actually leaving the text input in place and only scrolling the keyboard down. So I'm trying to change the toolbar to be input accessory. I have a photo image and a send button as well. Basically the same bar you see in WhatsApp and iMessage.
I need the bar to scroll down. Not just the keyboard.
// what do I put here? override func canBecomeFirstResponder() -> Bool { return true }
- Fix illegible macOS destructive alert button (SwiftUI)
-
SwiftUI Custom View Wrapper
I'm trying to figure out how to make a custom view which wraps normal SwiftUI content like this...I'm not sure if I use UIViewRepresentable or what. Please help.
CustomView { x in VStack { ... } }
-
Deferred Screenspace Decals in Metal
Trying to create deferred screenspace decals rendering in Metal by following this article. Though can't seem to figure it out...
These are bounds of the decal...
Actual result...
Potential issue
So apparently it doesn't think that the decal is intersecting the mesh, I'm sampling the depth value correctly, but then when calculating the actual position the the pixel in 3D space something doesn't add up.
Code
vertex VertexOut vertex_decal( const VertexIn in [[ stage_in ]], constant DecalVertexUniforms &uniforms [[ buffer(2) ]] ) { VertexOut out; out.position = uniforms.projectionMatrix * uniforms.viewMatrix * uniforms.modelMatrix * in.position; out.viewPosition = (uniforms.viewMatrix * uniforms.modelMatrix * in.position).xyz; out.normal = uniforms.normalMatrix * in.normal; out.uv = in.uv; return out; } fragment float4 fragment_decal( const VertexOut in [[ stage_in ]], constant DecalFragmentUniforms &uniforms [[ buffer(3) ]], depth2d<float, access::sample> depthTexture [[ texture(0) ]] ) { constexpr sampler textureSampler (mag_filter::nearest, min_filter::nearest); float2 resolution = float2( depthTexture.get_width(), depthTexture.get_height() ); float2 textureCoordinate = in.position.xy / resolution; float depth = depthTexture.sample(textureSampler, textureCoordinate); float3 viewRay = in.viewPosition * (uniforms.farClipPlane / in.viewPosition.z); float3 viewPosition = viewRay * depth; float3 worldPositon = (uniforms.inverseViewMatrix * float4(viewPosition, 1)).xyz; float3 objectPositon = (uniforms.inverseModelMatrix * float4(worldPositon, 1)).xyz; float distX = 0.5 - abs(objectPositon.x); float distY = 0.5 - abs(objectPositon.y); float distZ = 0.5 - abs(objectPositon.z); if(distX > 0 && distY > 0 && distZ > 0) { return float4(1, 0, 0, 0.5); } else { discard_fragment(); } }
EDIT:
Made a bit of a progress, now it at least renders something, it clips the decal box correctly once its outside of some mesh, but the parts on the mesh are still not completely correct.. to be exact it also renders sides of the box that are overlapping with the mesh under the decal (you can see it on the image below as the red there is a bit darker)
And to add more details, the depthTexture is passed from previous "pass" so it only contains the icosphere on it, and the decal cube shader doesn't write to the depthTexture, just reads from it.
and depth stencil is defined as...
let stencilDescriptor = MTLDepthStencilDescriptor() stencilDescriptor.depthCompareFunction = .less stencilDescriptor.isDepthWriteEnabled = false
and render pipeline is defined as...
let renderPipelineDescriptor = MTLRenderPipelineDescriptor() renderPipelineDescriptor.vertexDescriptor = vertexDescriptor renderPipelineDescriptor.vertexFunction = vertexLibrary.makeFunction(name: "vertex_decal") renderPipelineDescriptor.fragmentFunction = fragmentLibrary.makeFunction(name: "fragment_decal") if let colorAttachment = renderPipelineDescriptor.colorAttachments[0] { colorAttachment.pixelFormat = .bgra8Unorm colorAttachment.isBlendingEnabled = true colorAttachment.rgbBlendOperation = .add colorAttachment.sourceRGBBlendFactor = .sourceAlpha colorAttachment.destinationRGBBlendFactor = .oneMinusSourceAlpha } renderPipelineDescriptor.colorAttachments[1].pixelFormat = .bgra8Unorm renderPipelineDescriptor.depthAttachmentPixelFormat = .depth32Float
so the current issue is that it discards only pixels that are out of the mesh that its being projected on, instead of all pixels that are "above" the surface of the icosphere
New Shader Code
fragment float4 fragment_decal( const VertexOut in [[ stage_in ]], constant DecalFragmentUniforms &uniforms [[ buffer(3) ]], depth2d<float, access::sample> depthTexture [[ texture(0) ]] ) { constexpr sampler textureSampler (mag_filter::nearest, min_filter::nearest); float2 resolution = float2( depthTexture.get_width(), depthTexture.get_height() ); float2 textureCoordinate = in.position.xy / resolution; float depth = depthTexture.sample(textureSampler, textureCoordinate); float3 screenPosition = float3(textureCoordinate * 2 - 1, depth); float4 viewPosition = uniforms.inverseProjectionMatrix * float4(screenPosition, 1); float4 worldPosition = uniforms.inverseViewMatrix * viewPosition; float3 objectPosition = (uniforms.inverseModelMatrix * worldPosition).xyz; if(abs(worldPosition.x) > 0.5 || abs(worldPosition.y) > 0.5 || abs(worldPosition.z) > 0.5) { discard_fragment(); } else { return float4(1, 0, 0, 0.5); } }
-
UIImage created from MTLTexture is possibly corrupted
I have this color invert filter created with Metal. It does the job and the returned image can be set to a
UIImageView
.
But the problem arises when the image is converted to CGImage or CIImage or when I try to save it to Library.
Printing the image to console doesn't show any signs for corrupt data but I get an error when saving to the library saying"The operation couldn’t be completed. (PHPhotosErrorDomain error -1.)"
Here's the code:// ImageFilter.metal #include <metal_stdlib> using namespace metal; // Invert Colors half4 invertColor(half4 color) { return half4((1 - color.rgb), color.a); } kernel void drawWithInvertedColor(texture2d<half, access::read> inTexture [[ texture (0) ]], texture2d<half, access::write> outTexture [[ texture (1) ]], uint2 gid [[ thread_position_in_grid ]]) { half4 color = inTexture.read(gid).rgba; half4 invertedColor = invertColor(color); outTexture.write(invertedColor, gid); }
class MetalImageFilter { ... public func imageInvertColors(of image: UIImage) -> UIImage { let function = library.makeFunction(name: "drawWithInvertedColor")! let computePipeline = try! device.makeComputePipelineState(function: function) let textureLoader = MTKTextureLoader(device: device) let inputTexture = try! textureLoader.newTexture(cgImage: image.cgImage!) let width = inputTexture.width let height = inputTexture.height let textureDescriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .r32Float, width: width, height: height, mipmapped: false) textureDescriptor.usage = [.shaderRead, .shaderWrite] let outputTexture = device.makeTexture(descriptor: textureDescriptor)! let commandQueue = device.makeCommandQueue()! let commandBuffer = commandQueue.makeCommandBuffer()! let commandEncoder = commandBuffer.makeComputeCommandEncoder()! commandEncoder.setComputePipelineState(computePipeline) commandEncoder.setTexture(inputTexture, index: 0) commandEncoder.setTexture(outputTexture, index: 1) let threadsPerThreadGroup = MTLSize(width: 16, height: 16, depth: 1) let threadgroupsPerGrid = MTLSize(width: width/16 + 1, height: height/16 + 1, depth: 1) commandEncoder.dispatchThreadgroups(threadgroupsPerGrid, threadsPerThreadgroup: threadsPerThreadGroup) commandEncoder.endEncoding() commandBuffer.commit() commandBuffer.waitUntilCompleted() let ciImg = CIImage(mtlTexture: outputTexture)!.oriented(.downMirrored) let invertedImage = UIImage(ciImage: ciImg) return invertedImage } }
class ViewController: UIViewController { ... if let iImage = lib?.imageInvertColors(of: currentImage) { ... save(iImage) ... } else { print("No inverted image!") } } func save(_ photo: UIImage) { debugPrint(photo) PHPhotoLibrary.requestAuthorization(for: .addOnly) { _ in PHPhotoLibrary.shared().performChanges { PHAssetChangeRequest.creationRequestForAsset(from: photo) } completionHandler: { saved, error in dump(saved) dump(error?.localizedDescription) } } } }
What's wrong with the code?
-
Metal thread group performance delta
With a 2048 x 896 texture, I have been calling the following for a
MTLComputeCommandEncoder
:
[myEncoder dispatchThreadgroups:a threadsPerThreadgroup:b];
where "a" isMTLSize(256,30,1)
and "b" isMTLSize(8,8,1)
After I realized there's a better way with non-uniform thread groups on newer GPU hardware (since 10.13.x), I now see that the better way is to let the GPU figure it out:
NSUInteger w = pipeline.threadExecutionWidth;
NSUInteger h = pipeline.maxTotalThreadsPerThreadgroup/threadW;
MTLSize a = MTLSizeMake(texture.width, texture.height, 1);
MTLSize b = MTLSizeMake(w, h, 1);
[myEncoder dispatchThreads:a threadsPerThreadgroup:b];
where "a" isMTLSize(2048,896,1)
and "b" isMTLSize(64,16,1)
On Radeon Vega 48 hardware, what is the theoretical performance difference?