Update CGRectMake to CGRect in Swift 3 Automatically - ios

Now that CGRectMake , CGPointMake, CGSizeMake, etc. has been removed in Swift 3.0, is there any way to automatically update all initializations like from CGRectMake(0,0,w,h) to CGRect(x:0,y:0,width:w,height:h). Manual process is.. quite a pain.
Not sure why Apple don't auto convert this when I convert the code to Current Swift Syntax...

The simplest solution is probably just to redefine the functions Apple took away. Example:
func CGRectMake(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) -> CGRect {
return CGRect(x: x, y: y, width: width, height: height)
}
Put that in your module and all calls to CGRectMake will work again.

Short answer: don't do it. Don't let Apple boss you around. I hate CGRect(x:y:width:height:). I've filed a bug on it. I think the initializer should be CGRect(_:_:_:_:), just like CGRectMake. I've defined an extension on CGRect that supplies it, and plop that extension into every single project the instant I start.
extension CGRect {
init(_ x:CGFloat, _ y:CGFloat, _ w:CGFloat, _ h:CGFloat) {
self.init(x:x, y:y, width:w, height:h)
}
}
That way, all I have to do is change "CGRectMake" to "CGRect" everywhere, and I'm done.

Apple actually does provide this feature. All you have to do is go to:
Edit > Convert > To Latest Swift Syntax...
And then follow the onscreen prompts.
This will solve your syntax issues and you won't have to make new functions for all of the various removed functions.

Related

Images are overwritten when modifying a PDF iOS

I have an application that allows a user to draw on a PDF. The user's drawing is saved as an image which is then added to an existing PDF. The issue I encounter is when a user has already drawn 2 images. For some reason, saving the 3rd image cause the 2nd image to be overwritten by the first. Below is an example.
PDF example:
The PDF above should read First, Second, Third; however, the 2nd image was overwritten by the first.
Below is my code for embedding an image into the PDF. Note I also tried this with PDFKit and have experienced the same result:
func saveImageToPDF(path: String , drawnImage: UIImage, x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat, pageIndex: Int) {
if let pdf = CGPDFDocument(NSURL(fileURLWithPath: path)) {
let pageCount = pdf.numberOfPages
// Write to file
UIGraphicsBeginPDFContextToFile(path, CGRect.zero, nil)
for index in 1...pageCount {
let page = pdf.page(at: index)
let pageFrame = page?.getBoxRect(.mediaBox)
if (pageFrame != nil) {
UIGraphicsBeginPDFPageWithInfo(pageFrame!, nil)
let pdfContext = UIGraphicsGetCurrentContext()
// Draw existing page
pdfContext?.saveGState()
pdfContext?.scaleBy(x: 1, y: -1)
pdfContext?.translateBy(x: 0, y: -pageFrame!.size.height)
pdfContext?.drawPDFPage(page!)
pdfContext?.restoreGState()
// Draw image on top of page
if (index == (pageIndex + 1)) {
drawnImage.draw(in: CGRect(x: x, y: y, width: width, height: height))
}
}
}
UIGraphicsEndPDFContext()
}
}
Note: I only seem to encounter this issue on iOS 15. Running the same code on iOS 14 works like a charm.
Should I consider this a bug on iOS 15, or is there something I'm missing?
Thanks in advance!
After reaching out to Apple's technical support. They concluded it was an issue with iOS 15.
Here is a sample project that replicates the issue exactly: https://github.com/Manguelo/test-pdf-issue
Note the application should be run on iOS 15.0
According to the PDFKit team this bug should be addressed in iOS 15.2 beta 3.

Drawing a circular loader

I have to create a circular loader as per below image (Front is thicker than tail)
I am able to create a circular progress bar and also provided rotation animation.
below is code for circle
func circleFrame() -> CGRect {
var circleFrame = CGRect(x: 0, y: 0, width: 2 * circleRadius, height: 2 * circleRadius)
let circlePathBounds = circlePathLayer.bounds
circleFrame.origin.x = circlePathBounds.midX - circleFrame.midX
circleFrame.origin.y = circlePathBounds.midY - circleFrame.midY
return circleFrame
}
func circlePath() -> UIBezierPath {
return UIBezierPath(ovalIn: circleFrame())
}
Using above code I can create a circle of equal width but not like as displayed image.
Please guide me how to create a loader like above image (tail is thinner than front). Any idea or suggestion would be great.
The simplest approach might be to create the image you want to display and then rotate it, rather than trying to draw it from scratch.
I haven't tried the following tutorial but I'm including it as a sample of how this might be done:
https://bencoding.com/2015/07/27/spinning-uiimageview-using-swift/
Note that the GitHub version (linked on that page) includes a Swift 4 update.

Swift drawing code behaves differently on tvOS than iOS

The company that I work for has both an iOS and a tvOS version of an app. The app draws a script at the bottom for the user to keep up during a workout, like so:
This has worked fine for more than a year in any app targeted for iOS. However, when targeting tvOS, with the same drawing code, instead of drawing the way I would expect, the tvOS view has what I'll call "traces" left after drawing each line, as opposed to just having the one line for the current time.
The drawing code is as follows:
func addIndicatorLine(_ context:CGContext?, rect: CGRect, start: CGPoint, color: UIColor = UIColor.white) {
context!.translateBy(x: rect.origin.x, y: rect.height)
context!.scaleBy(x: 1.0, y: -1.0)
context!.setLineWidth(1.0)
context!.setStrokeColor(color.cgColor)
context!.move(to: CGPoint(x: start.x, y: 0))
context!.addLine(to: CGPoint(x: start.x, y: rect.size.height - 5))
context!.strokePath()
context!.scaleBy(x: 1.0, y: -1.0)
context!.translateBy(x: -rect.origin.x, y: -rect.height)
}
Am I missing something obvious, or is there something different I have to do for the tvOS version of the drawing code?
So after a couple of days of trying to figure this out, thanks to one answer (https://stackoverflow.com/a/43898524/2820553) that pointed out a line in the docs to me, I needed to give my view a background color, otherwise drawing errors may occur:
If the view’s opaque property is also set to YES, the backgroundColor property of the view must not be nil or drawing errors may occur.
Simply setting the view's background to a clear color solved this issue. Amazing that it didn't manifest in iOS but did in tvOS. Hope this helps anyone else looking for something similar.

Cannot seem to use CGRectIntegral and CGRectInset functions in Swift

Sorry for the novice question.
But just as the title says, I can't seem to use these functions in Swift 3. I have tried by importing the CoreGraphics library, but to no avail.
Does anyone know why?
Thanks in advance.
The functions are working fine, but their names have changed (a bit):
let frame = CGRect.zero
let x = frame.integral
frame.insetBy(dx: 0, dy: 0)
import CoreGraphics
let rect = CGRect()
let rectIntegral = rect.integral
Thanks:)
Actually you don't need to import CoreGraphics.
In Swift 3 Objective-C function
CGRect CGRectIntegral(CGRect rect)
has become
var integral: CGRect { get }
and
CGRect CGRectInset(CGRect rect, CGFloat dx, CGFloat dy);
has become
func insetBy(dx: CGFloat, dy: CGFloat) -> CGRect
Both API have to be called on the CGRect instance for example
let newFrame = view.frame.insetBy(dx: 10.0, dy:10.0)
A hint to find out yourself
Press ⇧⌘0
Type CGRectIn in the search field
In the popup menu set the language to Objective C
Select one of the functions
Set the language to Swift

Regular Expression to replace CGRectMake

As CGRectMake is not available in swift 3.0 and migrator did not convert it i need to manually replace it and it is used more than 300 times in my code so can anyone help me in this to develop regular expression so i can find and replace code. What i want to do is to convert
CGRectMake(a,a,a,a) here a is some value.
to
CGRect(x: a, y: a, w: a, h: a)
Find by this:
CGRectMake\(([^,]*),([^,]*),([^,]*),([^,]*)\)
and Replace by this:
CGRect\(x:\1, y:\2, w:\3, h:\4\)
Tried it in notepad++
EDIT - With Regex:
CGRectMake\(([^,]*),([^,]*),([^,]*),([a-z|0-9|.|A-Z]*)\)
and replace with
CGRect\(x:\1, y:\2, width:\3, height:\4\)
Using regex we can not get the value of x,y,width,height dynamically.
So Alternative solution to above is,
Replace all the CGRectMake( with
appdelegateobject.CGRectMakeWrapper("
At the end add " only.
Means in your case you will replace CGRectMake(a,a,a,a) to appdelegateobject.CGRectMakeWrapper("a,a,a,a"
where appdelegateobject is the appdelegate shared instance object where you will define CGRectMakeWrapper function having string parameter as shown below :
func CGRectMakeWrapper(str: String) -> CGRect {
var rect = CGRectZero
if(str.characters.count > 0)
{
var arr = str.componentsSeparatedByString(",")
if(arr.count == 4)
{
rect = CGRect(x: CGFloat((arr[0] as NSString).doubleValue), y: CGFloat((arr[1] as NSString).doubleValue), width: CGFloat((arr[2] as NSString).doubleValue), height: CGFloat((arr[3] as NSString).doubleValue))
}
}
return rect
}
var rect = "10.0,10.0,100,100" //String
var rect1 = CGRectMakeWrapper(rect) //CGRect
I have shown sample string as rect and passed to CGRectMakeWrapper function which will return a rect. You can define this CGRectMakeWrapper function in common class which is accessible to all classes(e.g Appdelegate file).
I have one different way to solve this problem.
Step 1
In the following line
CGRectMake(a,a,a,a)
Just replace CGRectMake with CGRectMakeCustom so all will look like
CGRectMakeCustom(a,a,a,a)
Step 2
Create new Global function in the project
as follows
func CGRectMakeCustom(x: Double, y: Double, width: Double, height: Double) -> CGRect
{
return CGRect(x: x, y: y, width: width, height: height)
}
In this way it will be easy for you to start woking on Swift3
You can change mode to regular expression while searching and search for:
CGRectMake\(([^,]*),([^,]*),([^,]*),([^,]*)\)
which should be replaced by
CGRect\(x:\1, y:\2, w:\3, h:\4\)

Resources