Do you need to release CGContextRef in Swift?
CFTypes are automatically managed unless explicitly specified as Unmanaged.
According to the documentation.
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html
Core Foundation objects returned from annotated APIs are automatically
memory managed in Swift—you do not need to invoke the CFRetain,
CFRelease, or CFAutorelease functions yourself. If you return Core
Foundation objects from your own C functions and Objective-C methods,
annotate them with either CF_RETURNS_RETAINED or
CF_RETURNS_NOT_RETAINED. The compiler automatically inserts memory
management calls when it compiles Swift code that invokes these APIs.
If you use only annotated APIs that do not indirectly return Core
Foundation objects, you can skip the rest of this section. Otherwise,
continue on to learn about working with unmanaged Core Foundation
objects.When Swift imports APIs that have not been annotated, the compiler
cannot automatically memory manage the returned Core Foundation
objects. Swift wraps these returned Core Foundation objects in an
Unmanaged structure.
Unmanaged types will have the type signature
func StringByAddingTwoStrings(CFString!, CFString!) -> Unmanaged<CFString>!
CGBitmapContextCreate
has the type signature
func CGBitmapContextCreate(...) -> CGContext!
Hence its managed automatically by swift.
How to correctly clean up the memory when creating a CGContextRef?
Yes. You do have to eventually free()
bitmapData (once the CGContext is done drawing etc.) if you malloc()
ed it.
See my (corrected) answer to your other question.
If you use the NULL option (i.e. if you do not malloc()
your bitmapData), I would expect the data pointer to be valid until you CGContextRelease()
your context. So you'd either need to do whatever you want to do with the data before releasing the context, or copy the bitmap data somewhere (in which case you could just as well malloc()
the memory beforehand and pass it to the context).
Converting Objective-C code to Swift: okay to omit release calls?
Per the docs:
Core Foundation types are automatically imported as full-fledged Swift classes. Wherever memory management annotations have been provided, Swift automatically manages the memory of Core Foundation objects, including Core Foundation objects that you instantiate yourself
So you can omit the calls.
Redrawing CGContext after it's already been drawn in Swift?
You need to do all of your drawing inside override func draw(_ rect: CGRect)
(or inside routines called from there). So your draw
needs a flag set outside (by your actions) to tell it which of your styles to draw. You trigger the redraw with setNeedsDisplay()
- but that should be called from your action, not from the drawing code. Your current func drawStyleOne()
tries to draw (but probably to an invalid currentContext) and then calls setNeedsDisplay()
, which just schedules your actual draw
routine to be run, which always draws the same "style".
The UIView
class works behind the scenes to do quite a lot - if makes sure that draw
isn't called unnecessarily, and schedules it when it is necessary, it figures out which parts of the view need re-drawn if they have been obscured (that's why it passes you a rect
), and it sets up the current graphics context for draw
, amongst other things.
See this Ray Wenderlich tutorial, or the Apple docs. As the Apple docs say:
For custom views, you must override the drawRect: method and perform
all your drawing inside it.
(my emphasis)
So your code should look something like this:
class VectorView: UIView {
public var whichStyle: SomeEnumOfYours = // your default value
override func draw(_ rect: CGRect) {
switch self.whichStyle {
case .style1:
self.drawStyleOne()
case .style2:
self.drawStyleTwo()
//...
}
}
}
//...
func styleButtonPressed() {
NSLog("STYLE BUTTON PRESSED")
_vectorView?.whichStyle = // whichever style required
_vectorView?.setNeedsDisplay()
}
How to correctly update a CGContext with a function call?
You should not call draw()
method directly ... You ca call setNeedsDisplay()
or layoutIfNeeded()
As per Apple docs
This method is called when a view is first displayed or when an event
occurs that invalidates a visible part of the view. You should never
call this method directly yourself. To invalidate part of your view,
and thus cause that portion to be redrawn, call the setNeedsDisplay()
or setNeedsDisplay(_:) method instead.
So your code becomes
public func updateMap(scene: GameScene){
x = scene.current_xcoords
y = scene.current_ycoords
let w = self.frame.width
let h = self.frame.height
drect = CGRect(x: (w/50) + CGFloat(x)*w/8, y: (h/100) + CGFloat(y)*h/8, width: (h / 11), height: (h / 11))
setNeedsDisplay()
}
Empty CGContext
I'm not sure what the code in the liked article would do, but two things are different with your Swift code.
bytesPerRow: width // width * 4 (== bitmapBytesPerRow)
space : NULL // CGColorSpaceCreateDeviceRGB()
The documentation of CGBitmapContextCreate
does not say anything about supplying NULL
for colorspace
, but the header doc says The number of components for each pixel is specified by space
, so, at least, CGColorSpaceCreateDeviceRGB()
is not appropriate for alphaOnly
(which should have only 1 component per pixel).
As far as I tested, this code returns non-nil CGContext
:
let bitmapBytesPerRow = width //<-
let bitmapByteCount = bitmapBytesPerRow * height
let pixelData = UnsafeMutablePointer<UInt8>.allocate(capacity: bitmapByteCount)
let context = CGContext(data: pixelData,
width: width,
height: height,
bitsPerComponent: 8,
bytesPerRow: bitmapBytesPerRow,
space: CGColorSpaceCreateDeviceGray(), //<-
bitmapInfo: CGImageAlphaInfo.alphaOnly.rawValue)
But, not sure if this works for your purpose or not.
CGContext AND CGContextRef the same in Swift? How does this work?
There's nothing particularly magical here. CGContextRef
and CGContext
are just different names for (almost) the same thing. Swift just blurs the typedef for you.
<CoreGraphics/CGContext.h>
typedef struct CGContext *CGContextRef;
See also the Using Swift with Cocoa and Objective-C guide section on Core Foundation:
When Swift imports Core Foundation types, the compiler remaps the names of these types. The compiler removes Ref from the end of each type name because all Swift classes are reference types, therefore the suffix is redundant.
They just chose not to take away the Ref
form of the name, I guess for old timers who are used to typing it :D
How do I get UIImage from a CGContextRef?
Something like this :
-(UIImage*)doImageOperation
{
// Do your stuff here
CGImageRef imgRef = CGBitmapContextCreateImage(context);
UIImage* img = [UIImage imageWithCGImage:imgRef];
CGImageRelease(imgRef);
CGContextRelease(context);
return img;
}
Related Topics
How to Hide the Navigationbar When Embedding Swiftui in Uikit
Using "If Let" with Logical "Or" Operator
Local Notification While App Not Running
Delete All Characters After a Certain Character from a String in Swift
Translucent Status Bar with No Navigation Bar
What Is Other Option Available in Swift Instead of Refactoring and Renaming Class or Attribute Name
Understanding Shorthand Closure Syntax for Map Function in Swift
How to Get Row Index in Swiftui List
Argument for Generic Parameter Could Not Be Inferred
How to Reload a UI View's Content Swift
How to Connect Localhost (With Invalid Certificate) Using Alamofire
Aws S3 Transfer Manager ${Cognito-Identity.Amazonaws.Com:Sub} Policy Variable Access Denied