Instruments: Call Tree View Is Your Friend

January 23rd, 2017

Filed under: Instruments | Be the first to comment!

On Stack Overflow I see the same question constantly from people who use Instruments. Instruments uncovers a problem with their app. The app could have memory leaks. It could use a lot of memory. The people asking the questions want to know how to find the area of their code that is causing the problem. I have answered questions like this multiple times on Stack Overflow. Rather than repeat myself, I will answer it here.

If you want to find the problem areas in your code with Instruments, switch to the call tree view. Select the Invert Call Tree and Hide System Libraries checkboxes to show your code in the call tree view. Double-click a function in the call tree view to find problem lines of code. More detailed information on switching to the call tree view can be found in the Allocations Instrument Call Tree section of the following article:

Getting Started with Instruments

Facebooktwittergoogle_plusredditmail

Limiting Device Orientations in an iOS App

January 8th, 2017

Filed under: iOS Development | Be the first to comment!

I’ve been developing an iOS Game that is meant to be played in landscape orientation. I had problems forcing the game to be played in landscape orientation, causing the game to be rejected by Apple the first time I submitted it.

Limiting an iOS app’s device orientations is trickier than you would expect. I didn’t find much information about this online so I’m writing about what I learned.

Setting Supported Device Orientations

The first step is to set the supported device orientations for your target in Xcode. Select the project from Xcode’s project navigator to open the project editor. Select the target in the project editor.

XcodeDeviceOrientation

In the Deployment Info section there’s a series of Device Orientation checkboxes. Select the checkboxes of the device orientations you want to support. My game is meant to be played in landscape orientation so I selected the two landscape checkboxes.

Supported iPad Orientations

When you set the supported device orientations for your app and test the app, you’ll notice something. On the iPhone the app will respect your supported device orientations. But on the iPad the app will support all four possible orientations. Why does the iPad do this?

The Info.plist file has a separate entry for supported iPad device orientations. Click the Info button at the top of the project editor to access the Info.plist file properties.

SupportediPadOrientations

When you examine the Supported interface orientations (iPad) entry, you will see the iPad initially supports all four device orientations. Remove the items for the orientations you don’t want to support. In my case this means removing the two portrait items.

Disabling iPad Multitasking Support

When you set the supported iPad orientations and test your app, it should respect your supported device orientations. But when you try to upload your app to the App Store, the app will be rejected because iPad multitasking requires your app to support all four device orientations.

The fix is to disable iPad multitasking support for your app. In the Deployment Info section for the target (Look at the first image in this article), there is a Requires full screen checkbox. Select that checkbox to disable iPad multitasking. With iPad multitasking support disabled you can upload your app to the App Store without having to support all four device orientations.

Facebooktwittergoogle_plusredditmail

Adding Markers to Text Lists when Pressing the Return Key

December 12th, 2016

Filed under: Cocoa, Mac Development | Be the first to comment!

I tried using Apple’s NSTextList class for creating ordered and unordered lists in an application I’m developing. I was able to create lists, but when I pressed the Return key inside an unordered list, no bullet was added.

Because of this flaw in NSTextList I decided to implement my own class for lists. But I still needed to insert markers when pressing the Return key inside the list. There is very little information available on how to insert list markers when pressing the Return key so I’m sharing what I’ve learned.

Perform the following steps to insert list markers when the Return key is pressed:

  1. Create a subclass of NSTextView.
  2. Override the function insertNewline in your NSTextView subclass. This function gets called when someone presses the Return key.
  3. Use the text view’s selectedRange property to determine if you’re inside a list. The selectedRange property’s location field is the text view’s insertion point.
  4. If you’re inside a list, add the marker to the text view’s text storage at the insertion point.

The following Swift code shows a simple example of overriding insertNewline to insert a bullet when someone presses the Return key inside an unordered list:

override func insertNewline(_ sender: Any?) {
    // Choose Edit > Emoji & Symbols in Xcode to enter the bullet character.
    let bullet = "•\t"
    let bulletToAdd = NSAttributedString(string: bullet)
    super.insertNewline(sender)
    if insideAList() {
        addMarker(marker: bulletToAdd, point: (selectedRange().location))
    }  
}

func addMarker(marker: NSAttributedString, point: Int) {
    textStorage!.insert(marker, at: point)
}

You’ll notice I didn’t provide the code for the insideAList function. That code depends on your application and how you store lists in the application. You have to get the ranges for the lists in your document. Check if the text view’s insertion point is in one of the ranges.

Facebooktwittergoogle_plusredditmail

NSTableView Disappearing Text

November 23rd, 2016

Filed under: Cocoa, Mac Development | Be the first to comment!

I was having a problem with disappearing text in a table view in a Mac application I’m developing. Selecting an item in the table view erased that item’s text from the table view. The table view is part of a split view. Dragging the split view’s divider erased the text from every item in the table view.

Finding the cause of the disappearing text was difficult. I had other projects with table views in a split view whose text wasn’t erased. I couldn’t see any differences in the projects whose table views kept their text and the project that erased the table view text.

I eventually discovered the cause of the disappearing table text: source list highlighting. Changing the table view’s highlighting from source list to regular fixed the issue. I can now drag the split view divider without erasing the text of every item in the table view.

Facebooktwittergoogle_plusredditmail

Maintaining NSTextView Insertion Point After Core Data Save

November 21st, 2016

Filed under: Cocoa, Mac Development | 1 comment

I am working on a Mac journaling application that uses Core Data. The user interface consists of a table view and a text view. The table view contains a list of dates. Selecting a date fills the text view with what was written on that date. Use the text view to write.

One problem I had was saving the text. Core Data is set up initially to save a text view or text field’s contents only when leaving the text view or text field. This behavior works fine for a contact form, but not for a journaling application. Core Data would save the text only when I selected a new date in the table view. With this behavior there’s potential for data loss.

I wrote some code to autosave the text view’s contents periodically. The saving worked, but every time I saved, the text view lost focus. When the text view lost focus, I had to click in the text view to resume typing. Autosaving provided a miserable typing experience. How could I autosave while allowing someone to keep typing? I had to perform the following steps:

  1. Call the NSTextView function selectedRange to save where the person was typing during the autosave.
  2. Call the NSWindow function makeFirstResponder to make the text view the first responder so the text view didn’t lose focus.
  3. Call the NSTextView function setSelectedRange to set the typing position back to where it was before the autosave.
  4. Call the NSText function scrollRangeToVisible to make the text view scroll to the point where the person was typing.

Here’s some Swift 3 code.

func updateTextViewAfterAutosave() {
    let insertionRange = textView.selectedRange()
    window.makeFirstResponder(textView)
    textView.setSelectedRange(insertionRange)
    textView.scrollRangeToVisible(insertionRange)
}

Make sure you don’t autosave too often. When I used this code to autosave after every change to the text view’s contents, the text view scrolling was visibly jumpy. Autosaving every 30 seconds worked well.

Facebooktwittergoogle_plusredditmail