PIXEL
DOCK

I like the smell of Swift in the morning…

Clocks run backwards in a SwiftUI world (aka how to draw an arc with SwiftUI)

Posted: | Author: | Filed under: iOS, Swift, SwiftUI | Tags: , | No Comments »

Sometimes you have to draw something on the screen that is not a full circle but only a part of the circle. Something like this:

The obvious way to do this would be to create a custom Arc Shape like this:

struct Arc: Shape {
    var startAngle: Angle
    var endAngle: Angle
    var clockwise: Bool

    func path(in rect: CGRect) -> Path {
        var path = Path()
        path.addArc(center: CGPoint(x: rect.midX, y: rect.midY),
                    radius: rect.width / 2,
                    startAngle: startAngle,
                    endAngle: endAngle,
                    clockwise: clockwise)
        return path
    }
}

Now we need to let SwiftUI know what kind of arc we want to draw. As a human I would describe the arc as starting at 90 degrees and ending at 180 degrees, because we are usually assuming that 0 degrees is at the top of a circle.

SwiftUI begs to differ. In SwiftUI 0 degrees means straight to the right. In other words:

Human 90 degrees == SwiftUI 0 degrees

Because of that we need to draw and arc from 0 degrees to 90 degrees. (I add a gray background, so we can see the frame of the arc)

struct ContentView: View {
    var body: some View {
        Arc(startAngle: .degrees(0),
            endAngle: .degrees(90),
            clockwise: true
        )
        .stroke(Color("pdMagenta"), lineWidth: 12)
        .frame(width: 200, height: 200)
    }
}

Seems pretty straightforward, but the result is a not what I would expect:

This is where things get wild. According to Apple’s docs SwiftUI (and UIKit) use a flipped coordinate system.

To explain what that means let’s have look at these two illustrations:

In a Cartesian coordinate system (that we humans are used to) increasing values on the Y-axis go up to the top. Resulting in the “clockwise” that we are used to.

In SwiftUI’s flipped coordinate system increasing values on the Y-axis are going down to the bottom of the canvas. And that results in a reversed “clockwise” direction. IMHO that is really counterintuitive, but that’s the way it is 🤷‍♂️
This is an excerpt from the Apple docs:
“In a flipped coordinate system … specifying a clockwise arc results in a counterclockwise arc”

In other words: Clocks run backwards in a SwiftUI context.

To get the arc we want we have to toggle the clockwise parameter in our custom ArcShape:

struct Arc: Shape {
    var startAngle: Angle
    var endAngle: Angle
    var clockwise: Bool

    func path(in rect: CGRect) -> Path {
        var path = Path()
        path.addArc(center: CGPoint(x: rect.midX, y: rect.midY),
                    radius: rect.width / 2,
                    startAngle: startAngle,
                    endAngle: endAngle,
                    clockwise: !clockwise)
        return path
    }
}

And now we get want we wanted in the first place:

NSXMLParserErrorDomain error 5

Posted: | Author: | Filed under: iOS | Tags: , | No Comments »

Trying to parse an XML file I came across this error message. According to the error message the parser could not parse the XML file so I suspected that my XML was malformed. But it wasn’t.

It turned out the problem was that I used the wrong method to load the XML file.

Instead of using:

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"demo.xml" ofType:nil];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL fileURLWithPath:filePath]];

I tried to do this:

NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL fileURLWithPath:@"demo.xml"]];

So the problem was that the Parser could not really load the XML. Strangely enough the parser loaded something because otherwise the parser’s init method should have returned nil. But whatever the parser loaded, it surely was not the right stuff. So be sure to get the XML file’s path from the main bundle and feed that to the parser’s init method.

UIFont: Problem when using more than 2 custom fonts of the same Font Family.

Posted: | Author: | Filed under: iOS | Tags: , | 4 Comments »

When you add custom fonts to your iPhone or iPad App you might experience the following problem: If you add more than 2 font variants of the same font family (e.g. “Normal”, “Bold” and “Extended”), only the last two font variants that you added to the project will be usable. The first variant (the one on top of your list) just won’t show up and is replaced by one of the two variants that were added last to the project.

The reason is quite simple: The iOS SDK apparently allows only 2 custom fonts of the same font family!

As a solution you could change the font-family of your font, so that not more than two font variants have the same font-family. Just to be clear: it’s not enough to change the file name of your font. You have to change all the references to the font-family inside your font files.

You can do this with with fontforge. Fontforge requires that you installed the X11 server on your system, but that should not be a problem as it is automatically installed when you install Xcode.

Make sure that you find all references to the font family name after you opened the font in Fontforge:

  1. Open your Font in Fontforge
  2. Goto ‘Element’ -> ‘Font Info’ and change the ‘Family Name’ field
  3. Goto ‘Element’ -> ‘TTF Names’ and change the fields ‘Family’ and ‘Preferred Family’
  4. Goto ‘File’ -> ‘Generate Fonts’ and save your edited font

With this little trick you should be able to use more than two variants of one font.

How to find an iPhone / iPad’s Document folder in Xcode

Posted: | Author: | Filed under: iOS, Xcode | Tags: , | No Comments »

Sometimes during development when you are writing or reading files from the Documents folder of an iOS Device it is quite useful to have a look at the devices filesystem. Or to the sandboxed Documents Folder of your app to be precise.

Here’s how you do it:

1. Developing on the Simulator

If you are using the iPhone / iPad Simulator for Development, the Documents folder is stored on your Mac’s harddrive:

/Users/user/Library/Application Support/iPhone Simulator/User/Applications/E599AF8C-D765-41A8-B593-A05D242CB701/Documents

You can also find the contents of the app’s “tmp” folder and the app’s preferences in the folder with the long and cryptic name. The only problem is to figure out what cryptic folder belongs to the current version of your app, because Xcode adds a new cryptic folder everytime you build your app in the simulator. So you probably have to find the right folder by looking at the folder’s timestamp.

2. Developing on the Device

Sometimes you have to use a “real” Device for Development. For example if you are using the iTunes File Sharing Feature which does not work on the Simulator. To find the device’s Document Folder for your app, follow this steps:

Xcode 3

  1. Open the Organizer Window in Xcode.
  2. Mark your Device in the left Column.
  3. Find your App in the “Applications” section on the bottom right.
  4. Click on the little triangle left of your App’s name.
  5. Drag the “Application Data” Bundle to your Desktop (or download it by clicking on the black arrow on the right)
  6. Open the downloaded folder (named something like: “com.yourcompany.appname 2011-02-24 10.50.14.277”) to find the Document Folder

Xcode 4

  1. Open the Organizer Window in Xcode.
  2. Mark your Device in the left Column.
  3. Click on “Applications” below your device (you might have to click on your device’s disclosure triangle to see these rows)
  4. On the right side you will see a list of your apps that are installed on this device.
  5. Click on your app’s “Download” Button
  6. Specify a save location and a folder containing your apps document folder will be saved.