NULL parameter in Swift - swift

In Objective-C, we can declare a function like this:
- (void)getRect:(CGRect *)aRectRef bRect:(CGRect *)bRectRef
{
if (aRectRef) *aRectRef = CGRectZero
if (bRectRef) *bRectRef = CGRectZero
}
and pass NULL to the function:
CGRect rect;
[self getRect:NULL bRect:rect]
There isn't NULL in Swift. I can't use nil as inout param directly either:
func getRect(aRect aRectRef: inout CGRect?, bRect bRectRef: inout CGRect?) -> Void {
...
}
self.getRect(&nil, bRect: rect) // <- ERROR
I must define a variable with nil value and pass it to the function, even though I don't need the variable totally.
How to pass nil to the function?
UPDATE:
null / nil in swift language just explained nil in Swift.
Swift optional inout parameters and nil explained how to define a variable with nil value and pass it as inout parameter.
I want to know there is a way to pass nil directly like &nil to function or not.

Your Objective-C method has nullable pointers as parameters,
in Swift 3 that would be an optional UnsafeMutablePointer:
func getRect(aRectRef: UnsafeMutablePointer<CGRect>?, bRectRef: UnsafeMutablePointer<CGRect>?) {
if let aRectPtr = aRectRef {
aRectPtr.pointee = CGRect(x: 1, y: 2, width: 3, height: 4)
}
if let bRectPtr = bRectRef {
bRectPtr.pointee = CGRect(x: 5, y: 6, width: 7, height: 8)
}
}
var rect = CGRect.zero
getRect(aRectRef: &rect, bRectRef: nil)
print(rect) // (1.0, 2.0, 3.0, 4.0)
So you can pass nil as an argument. What you can not do
(in contrast to Objective-C) is to pass the address of an uninitialized variable, rect must be initialized here.
The same can be written more compactly as
func getRect(aRectRef: UnsafeMutablePointer<CGRect>?, bRectRef: UnsafeMutablePointer<CGRect>?) {
aRectRef.map { $0.pointee = CGRect(x: 1, y: 2, width: 3, height: 4) }
bRectRef.map { $0.pointee = CGRect(x: 5, y: 6, width: 7, height: 8) }
}

Sorry, I am not allowed to add comment at this time, so I'll write this as an answer. In SWIFT, you defined the parameter as inout, you have to pass in a variable and not literal nil. You can do something like this,
func testGetRect()
{
var recta: CGRect? = nil
var rectb: CGRect? = CGRect()
self.getRect(aRect: &recta, bRect: &rectb)
}
func getRect(inout aRect aRectRef: CGRect?, inout bRect bRectRef: CGRect?) -> Void
{
if (aRectRef != nil)
{
aRectRef = CGRectZero
}
if (bRectRef != nil)
{
bRectRef = CGRectZero
}
}
Yes, you "must define a variable with nil and pass it to the function. I tried some casting to see if it work, but couldn't. The parameter passing with inout is like C++ parameter passing by reference, i.e foo(int &parama, int &paramb). You must pass a variables to foo. I don't believe SWIFT has parameter passing like the obj-c example that you have.

Related

Getting a `Type of expression is ambiguous without more context` when trying to returning a `some View` with a `ZStack` object

I'm trying to use CoreGraphics to draw some musical notes from a struct that is defined elsewhere in a swiftui App
func drawSheetMusic(in size: CGSize) -> some View {
return ZStack {
Color.clear.drawingGroup { ctx in
for note in self.musicData.notes {
let rect = CGRect(x: note.position.x - note.radius, y: note.position.y - note.radius, width: 2 * note.radius, height: 2 * note.radius)
ctx.cgContext.addEllipse(in: rect)
ctx.cgContext.setFillColor(Color.black.cgColor)
ctx.cgContext.fillPath()
}
return Rectangle().fill(Color.clear)
}
}
}
But this is returning an error Type of expression is ambiguous without more context on Line 2 there. What exactly am I doing wrong here?
func drawingGroup(opaque: Bool = false, colorMode: ColorRenderingMode = .nonLinear) -> some View
doesn't take a closure parameter. The problem becomes obvious if you remove the ZStack.
You seem to be confusing this with
UIGraphicsImageRenderer.image(actions: (UIGraphicsImageRendererContext) -> Void) -> UIImage

Swift protocol initializer precludes adding more stored properties to struct

TL;DR:
I want a protocol to provide default init behavior, but the compiler resists adopters adding more stored properties. I solved this with composition instead of inheritance, but what's wrong with my original approach?
Motivation
I want to automate the transformation of objects from design specifications to runtime specs. I use the example of scaling a CGSize but the intent is more general than just geometric layout. (IOW e.g. my solution won't be to adopt/reject/rewrite autolayout.)
Code
You can paste this right into a Playground, and it will run correctly.
protocol Transformable {
var size : CGSize { get } // Will be set automatically;
static var DESIGN_SPEC : CGSize { get } // could be any type.
init(size: CGSize) // Extension will require this.
}
// A simple example of transforming.
func transform(_ s: CGSize) -> CGSize {
CGSize(width: s.width/2, height: s.height/2)
}
// Add some default behavior.
// Am I sinning to want to inherit implementation?
extension Transformable {
init() { self.init(size: transform(Self.DESIGN_SPEC)) }
// User gets instance with design already transformed. No muss, fuss.
}
// Adopt the protocol...
struct T : Transformable {
let size: CGSize
static let DESIGN_SPEC = CGSize(width: 10, height: 10)
}
// ...and use it.
let t = T()
t.size // We get (5,5) as expected.
But every Eden must have its snake. I want a Transformable with another property:
struct T2 : Transformable {
// As before.
let size: CGSize
static let DESIGN_SPEC = CGSize(width: 10, height: 10)
let i : Int // This causes all sorts of trouble.
}
Whaa? Type 'T2' does not conform to protocol 'Transformable'
We have lost the synthesized initializer that sets the size member.
So... we put it back:
struct T3 : Transformable {
// As before.
let size: CGSize
static let DESIGN_SPEC = CGSize(width: 10, height: 10)
let i : Int
init(size: CGSize) {
self.size = size
self.i = 0 // But this is a hard-coded value.
}
}
But now our new member is statically determined. So we try adding another initializer:
struct T4 : Transformable {
// As before.
let size: CGSize
static let DESIGN_SPEC = CGSize(width: 10, height: 10)
let i : Int
init(size: CGSize) { self.size = size ; self.i = 0 }
// Try setting 'i':
init(i: Int) {
self.init() // Get the design spec properly transformed.
self.i = i // 'let' property 'i' may not be initialized directly;
} // use "self.init(...)" or "self = ..." instead
}
Declaring i as var shuts the compiler up. But i is immutable, and I want i that way. Explain to me why what I want is so wrong... This page is too small to include all the variations I tried, but perhaps I have missed the simple answer.

Stream remote framebuffer into NSView

I'm trying to implement a simple VNC client in Swift using LibvnccClient.
I have created a subclass of NSView. I create a CGContext and pass the data pointer to the library for use as the framebuffer. libvncclient updates the framebuffer as contents of the screen changes and calls my provided callback.
Here is the relevant code
class VNCClient {
var localClient: rfbClient
var view: NSView
init(view: NSView) {
guard let client_ptr = rfbGetClient(8, 3, 4) else {
fatalError("Trouble")
}
self.view = view
self.localClient = client_ptr.pointee
localClient.MallocFrameBuffer = resize
localClient.GotFrameBufferUpdate = update
let fbPointer = UnsafeMutablePointer<UInt8>(OpaquePointer((view as! RFBView).buffer))
localClient.frameBuffer = fbPointer
rfbClientSetClientData(&localClient, &viewTag, &self.view)
var argc: Int32 = 0
let b = rfbInitClient(&localClient, &argc, nil)
if b == RFB_TRUE {
print("Connected!")
}
Timer.scheduledTimer(withTimeInterval: 0.001, repeats: true) {_ in
if WaitForMessage(&self.localClient, 1) > 0 {
HandleRFBServerMessage(&self.localClient)
}
}
}
func update(client: UnsafeMutablePointer<rfbClient>?, x: Int32, y: Int32, w: Int32, h: Int32) -> Void {
let cl = client!.pointee
let view_ptr = rfbClientGetClientData(client, &viewTag)
let view = view_ptr?.assumingMemoryBound(to: RFBView.self).pointee
view?.setNeedsDisplay(NSRect(x: Int(x), y: Int(y), width: Int(w), height: Int(h)))
}
class RFBView: NSView {
let ctx = CGContext(data: nil, width: 800, height: 600, bitsPerComponent: 8, bytesPerRow: 4 * 800, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGImageAlphaInfo.noneSkipLast.rawValue)!
var buffer: UnsafeMutableRawPointer? {
return ctx.data
}
override func draw(_ dirtyRect: NSRect) {
let image = ctx.makeImage()
NSGraphicsContext.current()?.cgContext.draw(image!, in: frame)
}
It works but the display is not smooth. The server is running on the same machine in a VM so no network issues.
I'm redrawing the whole image for every update which I assume is the cause of the problem. So how can I redraw only the part of the framebuffer that is updated?
Is CoreGraphics fast enough for this or should I use NSOpenGLView?
I assumed that HandleRFBServerMessage would call update function once per iteration if there was an update. But that is not the case.
I replaced update with a stub that printed to console, and noticed it was being called more than thousand times when there was a lot of activity on the screen.
However, with the setNeedsDisplay call inside update, it was only being called a few hundred times. Since it was spending too much time rendering it was missing out on a few frames in between.
I moved the drawing code inside the Timer and it works perfectly now.
localClient.GotFrameBufferUpdate = { _, _, _, _, _ in needs_update = true }
Timer.scheduledTimer(withTimeInterval: 0.016, repeats: true) {_ in
if needs_update {
view.display()
needs_update = false
}
if WaitForMessage(&self.localClient, 1) > 0 {
HandleRFBServerMessage(&self.localClient)
}
}

How can I handle different types using generic type in swift?

I'm trying to write a class which allows me to easily interpolate between two values.
class Interpolation
{
class func interpolate<T>(from: T, to: T, progress: CGFloat) -> T
{
// Safety
assert(progress >= 0 && progress <= 1, "Invalid progress value: \(progress)")
if let a = from as? CGFloat, let b = to as? CGFloat
{
}
if let a = from as? CGPoint, let b = to as? CGPoint
{
}
if let from = from as? CGRect, let to = to as? CGRect
{
var returnRect = CGRect()
returnRect.origin.x = from.origin.x + (to.origin.x-from.origin.x) * progress
returnRect.origin.y = from.origin.y + (to.origin.y-from.origin.y) * progress
returnRect.size.width = from.size.width + (to.size.width-from.size.width) * progress
returnRect.size.height = from.size.height + (to.size.height-from.size.height) * progress
return returnRect // Cannot convert return expression of type 'CGRect' to return type 'T'
}
return from
}
}
Unfortunately, it gives me an error at return returnRect: Cannot convert return expression of type 'CGRect' to return type 'T'. Maybe I'm not understanding how generics are used...I just want to have one function that will handle interpolating between various types, rather than having a bunch of functions like func interpolate(from: Int, to: Int), func interpolate(from: CGPoint, to: CGPoint), etc.
The problem is that T is a generic placeholder – meaning that you cannot know what the actual concrete type of T is from within the function. Therefore although you are able to conditionally cast from and to to a CGRect (thus establishing that T == CGRect), Swift is unable to infer this information and therefore prohibits attempting to return a CGRect when it expects a return of T.
The crude solution therefore is to force cast the return result back to T in order to bridge this gap in information with the type-system:
if let from = from as? CGRect, let to = to as? CGRect {
// ...
return returnRect as! T
}
However, this kind of type-casting is really a sign that you're fighting the type-system and not taking advantage of the static typing that generics offer, and therefore is not recommended.
The better solution, as #Wongzigii has already said, is to use a protocol. For example, if you define an Interpolate protocol as he shows in his answer – you can then use this protocol in order to constrain your generic placeholder T in your interpolate function:
class Interpolation {
class func interpolate<T:Interpolate>(from: T, to: T, progress: CGFloat) -> T {
// Safety
assert(progress >= 0 && progress <= 1, "Invalid progress value: \(progress)")
return T.interpolate(from: from, to: to, progress: progress)
}
}
This solves many of your problems – it does away with the runtime type-casting and instead uses the protocol constraint in order to call the specialised interpolate function. The protocol constraint also prevents you from passing any types that don't conform to Interpolate at compile-time, and therefore also solves the problem of what to do when your type-casting fails.
Although that being said, I actually quite like the solution that #JoshCaswell suggested in his answer to your other question – overloading operators in order to achieve this functionality. As with the previous solution, the key is to define a protocol that encapsulates the functionality you're defining on each type, and then constrain your generic function to this protocol.
A simple implementation may look like this:
protocol Interpolatable {
func +(lhs:Self, rhs:Self) -> Self
func -(lhs:Self, rhs:Self) -> Self
func *(lhs:Self, rhs:CGFloat) -> Self
}
func +(lhs:CGRect, rhs:CGRect) -> CGRect {
return CGRect(x: lhs.origin.x+rhs.origin.x,
y: lhs.origin.y+rhs.origin.y,
width: lhs.size.width+rhs.size.width,
height: lhs.size.height+rhs.size.height)
}
func -(lhs:CGRect, rhs:CGRect) -> CGRect {
return CGRect(x: lhs.origin.x-rhs.origin.x,
y: lhs.origin.y-rhs.origin.y,
width: lhs.size.width-rhs.size.width,
height: lhs.size.height-rhs.size.height)
}
func *(lhs:CGRect, rhs:CGFloat) -> CGRect {
return CGRect(x: lhs.origin.x*rhs,
y: lhs.origin.y*rhs,
width: lhs.size.width*rhs,
height: lhs.size.height*rhs)
}
extension CGRect : Interpolatable {}
extension CGFloat : Interpolatable {}
class Interpolation {
class func interpolate<T:Interpolatable>(from: T, to: T, progress: CGFloat) -> T {
assert(progress >= 0 && progress <= 1, "Invalid progress value: \(progress)")
return from + (to - from) * progress
}
}
It would be nice if you use Protocol to scale your generic type.
protocol Interpolate {
associatedtype T
static func interpolate(from: T, to: T, progress: CGFloat) -> T
}
Then let CGRect extension conform to your protocol:
extension CGRect: Interpolate {
typealias T = CGRect
static func interpolate(from: T, to: T, progress: CGFloat) -> CGRect.T {
var returnRect = CGRect()
returnRect.origin.x = from.origin.x + (to.origin.x-from.origin.x) * progress
returnRect.origin.y = from.origin.y + (to.origin.y-from.origin.y) * progress
returnRect.size.width = from.size.width + (to.size.width-from.size.width) * progress
returnRect.size.height = from.size.height + (to.size.height-from.size.height) * progress
return returnRect
}
}
var from = CGRect(x: 0, y: 0, width: 1, height: 1) // (0, 0, 1, 1)
var to = CGRect(x: 1, y: 1, width: 0, height: 0) // (1, 1, 0, 0)
CGRect.interpolate(from, to: to, progress: 1) // (1, 1, 0, 0)
Also, this would make NSString conform to protocol Interpolate easily, like:
extension NSString: Interpolate {
typealias T = NSString
static func interpolate(from: T, to: T, progress: CGFloat) -> NSString.T {
//...
return ""
}
}

Missing argument for paramater #1 in call

I have this function and variable:
var trianglePlacement: CGFloat
func setPlacmentOfTriangle(trianglePlacementVal: CGFloat) {
trianglePlacement = trianglePlacementVal
}
I use the function later to do a calculation for this variable:
var trianglePosition: CGFloat = setPlacmentOfTriangle() * width
I am getting a Missing argument for parameter #1 in call error, okay makes sense, I am not passing in an argument.
Is there are way to get rid of the error without getting rid of the argument and not passing in an argument? These are the only times they show up in my code.
In case you are curious, this is the variable width:
var width: CGFloat = self.menubar.frame.size.width
Yes, there is a way you can call the function without passing in an argument. You can provide a default value to the function parameter like so:
func setPlacmentOfTriangle(trianglePlacementVal: CGFloat = 1.0) {
trianglePlacement = trianglePlacementVal
}
Then you call it like this:
setPlacmentOfTriangle()
If you call the setPlacmentOfTriangle function, it will use a value of 1.0 anytime you don't provide your own argument.
I would guess that this is a simplified example, but this function is not necessary at all. You really should just set the value of trianglePlacement directly, and not use a function like you are. Also, this line won't work:
var trianglePosition: CGFloat = setPlacmentOfTriangle() * width
The setPlacmentOfTriangle function doesn't return a value, so there is nothing to multiply with width.
// This is not very functional, avoid mutating other scopes
var trianglePlacement: CGFloat = 0
func setPlacmentOfTriangle(trianglePlacementVal: CGFloat) {
trianglePlacement = trianglePlacementVal
}
// this is better
var trianglePlacement: CGFloat = 0
func setPlacmentOfTriangle(trianglePlacementVal trianglePlacementVal: CGFloat) -> CGFloat {
return trianglePlacementVal
}
// this is a function with a default param value
var trianglePlacement: CGFloat = 0
func setPlacmentOfTriangle(trianglePlacementVal trianglePlacementVal: CGFloat = 0.0) -> CGFloat {
return trianglePlacementVal
}
This is because setPlacmentOfTriangle should take in a CGFloat as a parameter and you're not sending it one
If you do not always want to pass an argument then you can make it optional like so:
func setPlacmentOfTriangle(trianglePlacementVal: CGFloat?) {
if let tri = trianglePlacementVal as? CGFloat {
trianglePlacement = tri
}
}
Then you can pass nil as your parameter:
setPlacmentOfTriangle(nil)