Regular Expression to replace CGRectMake - ios

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\)

Related

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

Update CGRectMake to CGRect in Swift 3 Automatically

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.

Accessing CGRect values directly vs normalizing them in Swift - Objective-C rules still valid?

This question is inspired by Andrew Carter's comment on a previous question about the new CGSize initializer in Swift.
The Apple Docs for CGGeometry say:
... your applications
should avoid directly reading and writing the data stored in the
CGRect data structure. Instead, use the functions described here to
manipulate rectangles and to retrieve their characteristics.
Is Apple's recommendation to not directly access the data in a CGRect still valid with Swift? Why should CGRectGetMidX, CGRectGetWidth, etc. be used in place of accessing the values of a CGRect struct directly, when these properties are now exposed with Swift's new extension on CGRect?
Consider a non-standard CGRect with a negative width and height:
var rect = CGRect(x: 0.0, y: 0.0, width: -10.0, height: -10.0)
This is a valid rectangle according to the Apple docs, as "a rectangle with an origin of [0.0, 0.0] and a size of [10.0, 10.0] is exactly equivalent to a rectangle with an origin of [10.0, 10.0] and a size of [-10.0, -10.0]."
You can standardize this CGRect by calling the legacy inline CGRectStandardize method like in Objective-C, or any of the new methods provided on the Swift extension of CGRect:
CGRectStandardize(rect) // {x -10 y -10 w 10 h 10}
rect.standardized // {x -10 y -10 w 10 h 10}
rect.standardizeInPlace() // {x -10 y -10 w 10 h 10}
But wait! This will reposition your rect on the coordinate plane, not only making your width and height positive, but making your origin negative to reflect the initial position of the rect with its negative width and height.
The inline CGRectGet functions provide an interface to normalize a specific value of your rect, without changing its origin. Swift provides an extension on CGRect so you can access the normalized values directly, rather than using the legacy C methods provided by CGGeometry:
var rect = CGRect(x: 0.0, y: 0.0, width: -10.0, height: -10.0)
rect.size.width // non-normalized, returns -10
CGRectGetWidth(rect) // bridged C function, normalized, returns 10
rect.width // new from Swift extension on CGRect, normalized, returns 10
The new interfaces:
extension CGRect {
// ...
public var width: CGFloat { get }
public var height: CGFloat { get }
public var minX: CGFloat { get }
public var midX: CGFloat { get }
public var maxX: CGFloat { get }
public var minY: CGFloat { get }
public var midY: CGFloat { get }
public var maxY: CGFloat { get }
// ...
}
So the answer is yes, the same rules for CGRect in Objective-C apply in Swift as well. The only difference here is that Swift provides an extension on some CGGeometry structs which allow you to move away from the old inline C functions bridged from the CGGeometry headers.
In Swift 3, it looks like CGRectGetWidth() is replaced by CGRect.width.

Using variables in CGRectMake, Swift, UIkit

For an App I'm making i need to use variables to change the size and position of objects (Labels). I've tried var example = CGRectMake(0, 0, 0, 100), hoping it would ignore the zeros (Not really thinking it would though). I then tried:
var example = 100
Label1.frame = CGRectMake(20, 20, 50, example)
I changed the syntax a bit, adding "" and replacing the CGRectMake with CGRect etc, but nothing worked... I don't get what I'm doing wrong here... Help!
Below is the new syntax used since Swift 3.
CGRect(x: 0, y: 0, width: 100, height: 100)
CGRectMake takes CGFloats for all of its arguments. Your sample code should work fine if you specify that example is supposed to be a CGFloat, using a type identifier:
// v~~~~ add this...
var example: CGFloat = 100
Label1.frame = CGRectMake(20, 20, 50, example)
Otherwise, swift infers the type of example to be Int, and the call to CGRectMake fails, cuz it can't take an Int as a parameter...
So, there is many ways to skin the cat. It all depends what your needs and requirements are (maybe you could elaborate a bit on what you are trying to achieve?). But one way to do it could be to set a variable when something happens, and then update the frame of the label. If you added a tap gesture recognizer to your view, and updated your label like so:
let myLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
let tapGestRecog = UITapGestureRecognizer(target: self, action: "handleTap:")
self.view.addGestureRecognizer(tapGestRecog)
}
func handleTap(sender:UIGestureRecognizer) {
let newXposition = sender.locationInView(self.view).x
let newYposition = sender.locationInView(self.view).y
myLabel.frame = CGRectMake(newXposition, newYposition, 200, 200)
}
This is just an example, and a very crude way of doing it. There are many other ways of doing it, but it hopefully gives you an idea of how to achieve it.
Swift allows syntax that Objective-C does not:
var example = 100
label.frame.size.height = example
In objective-C you would have to do it differently:
CGRect frame = label.frame; //Create a temporary rect to hold the frame value
frame.size.height = example;
label.frame = frame;

Fixing bugs in a github project SwiftChart

I'm trying to track down the errors in this github project.
https://github.com/gpbl/SwiftChart
The owner doesn't seem to answer any questions or respond.
I can't get this example to run:
// Create a new series specifying x and y values
let data = [(x: 0, y: 0), (x: 0.5, y: 3.1), (x: 1.2, y: 2), (x: 2.1, y: -4.2), (x: 2.6, y: 1.1)]
let series = new ChartSeries(data)
chart.addSerie(series)
Xcode gives this error in regards to the data
ViewController.swift:41:31: '(Double, Double)' is not identical to 'Float'
in the main file Chart.swift, there is this section of code
var labels: [Float]
if xLabels == nil {
// Use labels from the first series
labels = series[0].data.map( { (point: ChartPoint) -> Float in
return point.x } )
}
else {
labels = xLabels!
}
I'm not quite sure how to deal with the map .
There are typos in the realm. It should read
let data = [(x: 0, y: 0), (x: 0.5, y: 3.1), (x: 1.2, y: 2), (x: 2.1, y: -4.2), (x: 2.6, y: 1.1)]
let series = ChartSeries(data)
chart.addSeries(series)
That being said, Swift by default infers 0.5 to be a Double, and his default init is looking for x and y to be of type Float.
I forked the repository, and added an init that will convert the doubles to float. This could obviously cause an issue if the double is too big, but for the small numbers it likely won't be an issue. I also added the example in question to the actual project. My fork is here.
I'll send a pull request if the owner wants to accept the changes. Otherwise, if I have time I may refactor it to all be Double and get rid of the extra init.
I added the following init in ChartSeries.swift, this prevents you from always having to define your array as it convert the array of Double value tuples to Floats.
init(data: Array<(x: Double, y: Double)>) {
self.data = data.map ({ (Float($0.x), Float($0.y))})
}

Resources