Category Archives: Xcode 6
Showing a popover underneath a piece of selected text is a trick widely made use of across OSX, not least in Xcode itself, but also in many other apps. In this post we’re going to look at a simple way to achieve this effect.
1. First of all, in IB drag out a Popover and View Controller and drop them in the Document Outline area. Drag a custom view to the canvas, and hook them all up thus:
delegate –> App Delegate (or class that will control the Popover)
Popover View Controller’s Outlets
view –> Custom View
Click the Popover object in the Outline area, and in the Attributes Inspector, set the Behaviour to Transient.
In the appDelegate.h file, or the .h file of the class that will control your popover, include the PopoverDelegate in the @interface declaration:
@interface AppDelegate : NSObject <NSApplicationDelegate, NSPopoverDelegate>
2. Still in the header file, you need to make sure the window that the NSTextView is in has a View outlet in its header file.
@property (weak) IBOutlet NSView *aView;
For my purposes, I just have a single window in the appDelegate class, so I just created a view property by control-dragging out of the Window’s view object to the header file. You’ll need to switch to the dual-view Assistant editor to do this:
While you’ve got the Assistant editor open, drag out an outlet from the Popover to the .h file and name it ‘popover’. Finally, in the same way create a similar outlet for your TextView.
4. Next, go into the implementation .m file for the appDelegate (or you class). You’ll need an IBAction to trigger the showing of the popover. In my case, I have an ‘Enter’ button the user hits after making a selection attached to a method I called enterSelection:(NSButton *)sender.
In this method, I first get the rect for the user’s selection with:
NSRect rect = [_textView firstRectForCharacterRange:[_textView selectedRange] actualRange:NULL];
That will return a rect in screen coordinates for the selected text. However, I need to convert that into the window’s coordinates with:
NSRect converted = [_window convertRectFromScreen:rect];
Now we’re ready to call the popover by supplying this rect to the first parameter and the View property we created earlier to the second parameter:
[self.popover showRelativeToRect:converted ofView: _aView preferredEdge:NSMinYEdge];
And that’s it. Your popover should show underneath the selected text whenever your method gets called. If you want to see how this is done step by step in Xcode, check out the video:
Xcode being the vast IDE that it is, it’s sometimes the simplest things that flummox you. It’s rare that I ever want to look at the XML code for any of my interface files, unless I’m copying one from one project to another or hunting down some forgotten outlet that’s throwing a warning. But when I do, I invariably forget how to get back to IB view.
If that’s you, fortunately it’s easy to return to the Interface Builder view from the source code view. Just right-click (aka ‘Control click’) on your nib file in the project navigator sidebar and choose “Open as…” and “Interface Builder XIB Document”. Unlike myself, you’ll remember that for next time, too (me, I’ll be looking for this post again in six months time! 🙂 ).
Here’s a little problem and solution I ran into the other day while using UITableView. I wanted to have a master-detail set up in which the UITableView was segued to after an initial home screen.
The problem occurred whenever I added or deleted something in the UITableView, segued back to the home page and then returned to the table view. Sometimes the table would not update. Going out and back into the view a second time, however, would finally reload my data and show me the changes. Why was my app needing to load the view twice before the table would show any changes?
Logging showed me that something even weirder was going on: Every time I segued into the table view, the viewDidLoad method was being called not once, but twice. So basically, to get my updated data to show, I was actually calling viewDidLoad four times!
I worked through a whole bunch of stackexchange posts related to various problems and solutions with the reloadData method — adding delays, removing it from any edit- or insert- methods and so on, calling it on the main thread — but the problem stubbornly remained.
Then I noticed something else. In my awakeFromNib method, the call to super had somehow got pushed to the end of the method, after a bunch of other set up calls. I’m not sure how it got there, but I did remember seeing a WWDC 2014 Swift video pointing out that one difference between Objective-C and Swift was that calls to super need to be made after doing any initial set up in Swift’s case, but before for Objective-C. Since this was an Obj-C project, what was my call to super doing at the end of the method?
And as if by magic, moving [super awakeFromNib] to the beginning of my awakeFromNib method resulted in viewDidLoad only being called once, and my table view updating correctly.
Though I found quite a few threads with people having a similar problem with UITableView’s needing two calls before updating, I haven’t come across this particular solution to (or cause of) the problem. Hopefully, this post will save someone else a few hours of head scratching!
If you’re not yet using source control with your Xcode projects, it’s something you want to seriously consider before a project you’re working on hits serious trouble. Setting up source control is easy when you create a new project (just tick the box in the project set up window), but figuring out how to add it to projects you’ve already created is a bit more challenging. In this post we’ll look at the ‘why’ and the ‘how’ of adding source control to an existing project.
In most normal applications, ‘Command-S’, Versions, Time Machine or other back up will save your hide when you either lose a document or realise a whole bunch of recent changes are something of a disaster. Recovering or reverting a document are mechanisms Apple has put a lot of time and effort into since Lion first appeared (changes I haven’t always been a fan of…).
However, these mechanisms do not work well with Xcode due to the complex and deep links between files in an Xcode build. If you’ve ever tried to go back to an earlier version of an Xcode project or undo some change from last week, and ended up with a headache, you’ll know what I’m talking about.
That’s what snapshots are for, you say? Yes, maybe. When they work. But in my experience snapshots themselves get lost, corrupted, or simply fail to restore.
Moreover, source control has other benefits aside from recovery and reversion that neither snapshots or any other mechanism provide. It’s primary purpose is to allow you to develop parallel but different versions of your project at the same time (a process known as ‘forking’). What if you want to experiment with adding some new feature, but don’t want to risk making changes right across your code that would be needed to try it out? What if you want to create one version of your project for one set of users and another one for others, or one version for an earlier OS X iteration and another for the current release?
Let’s get down to the nitty gritty. Let’s assume you’re convinced you want to add source control to your current project. The first thing you’ll need to do is install git if you haven’t already. If you’re not sure, open Terminal and enter
If you get back a version number, continue on to the next step. If not, you’ll need to install git first. Follow the instructions for doing that here and then return to this post.
Once git is installed, here’s the steps for adding source control to your existing repository:
1. Locate the project folder
Select the project in the sidebar on the right, and click the little ‘Open in Finder’ arrow on the right.
Once you’ve got the parent folder open in ‘Finder’, quit Xcode.
2. Open Terminal and switch to the project’s parent folder
Click on the project’s parent folder icon in Finder and drag it to a Terminal.app window. Hit ‘control-A’ on your keyboard to move the cursor to the beginning of the line and type ‘cd’. Press ‘return’ to complete the command.
I always like to do a quick ‘ls’ to double check I’m in the folder I think I am, and that it contains what I think it does.
git add .
git commit -m "Initial commit"
Notice that there’s a period after a space on the end of the second command. Don’t forget to include it.
4. Confirm your local repository
Reopen Xcode, and hit the ‘Source Control’ menu. You should now see the options are active.
You’ll notice that when you make changes in your Xcode project, an ‘M’ (‘modified) will appear next to the files that have been changed. When you’re happy that these are changes that you’re going to keep, use Source Control > Commit. Full documentation on how to use the various features of source control are available in Xcode’s documentation.
5. Add a remote repository
Local repositories are great, and may be enough for your needs, but for ultimate protection (such as against disk loss or failure), you might want to add remote back up. To do that, you’ll need an account with a service like GitHub or Bitbucket. My own personal preference is Bitbucket, largely because they allow you to have private repositories on a free account. Steps for adding your existing project to a remote repository can be found on your chosen service’s website. If you’re using Bitbucket, the general method is first create a new repository on the Bitbucket site and copy the link. Then, enter each of the following in Terminal, replacing the dummy text in square brackets with your actual values (remove the square brackets, too).
cd [path to your repo]
git remote add origin [url to your repository]
git push -u origin --all
git push -u origin --tags
After that, re-open your project in Xcode and you should be all set up. Check by ensuring the remote path is shown in Source Control > –> master > Configure…