/dev/trouble
Eric Roller's Development Blog

macOS

Everything related to development for Macintosh.

MacOS: Internet Recovery

- Posted in macOS by

Starting off with a replaced internal SSD on a MacBook Air, it doesn’t boot, obviously. It is necessary to boot into “Internet Recovery Mode” by selecting Command-R at startup, or, as I did, Option-Command-R to recover onto High Sierra.

I erase the disk in Disk Utility and select to install macOS High Sierra. After a few seconds I am greeted with the error:

The Recovery Server Could Not Be Contacted

A number of possible solutions are listed on the Mac OS X Blog. I used the first one, except that using sudo was not possible (command not found ?); I ran date in the Terminal which confirmed that the date was wrong, then I updated it using Apple’s time server (without sudo):

% ntpdate -u time.euro.apple.com

The run date once more to check that the date & time has been updated.

Back in the High Sierra installer, I get asked to select a destination Disk, but my internal SSD cannot be selected, because:

This disk doesn’t use the GUID Partition Table Scheme

The solution is to use Disk Utility to erase the drive, but in the High-Sierra version of Disk Utility, I had no such option to select the partitioning scheme!!! The Partition button is disabled.

I eventually solved it by rebooting into the old recovery mode (Command-R) and using Lion’s Disk Utility to reformat the drive, before returning to the new recovery mode (Option-Command-R). Checking again in Disk Utility looks fine.

Setup

The following steps are:

  • Create a default (admin) user as part of the installation, but don’t use the usual name to avoid conflicts later. Try "Migrator".
  • Do NOT create a standard user.
  • Connect the Time Machine Backup drive and enter its password.
  • Launch Migration Assistant and restore from the Time Machine backup.
  • Restore all files, including those of our standard user (write down the temporary password). Promote the admin user to be admin.
  • Wait for an hour...
  • Re-install applications (which have not been backed-up).
  • Login, change password, re-authenticate iCloud.
  • Correct file ownership of the Things database, from the admin account:

    % sudo chown gollum "/Users/gollum/Library/Containers/com.culturedcode.things/Data/Library/Application Support/Cultured Code/Things/ThingsLibrary.db"
    
  • Delete the Migrator user.

Here are the symptoms: open System Preferences, select Desktop & Screen Saver and click on the Screen Saver tab. In the list of the screen savers, I had an RSS feed which turned out just to be too slow for my aging machine.

However, selecting the feed to delete it just gave me the beach ball, rendering System Preferences totally unresponsive. I gave up after a few minutes. To close System Preferences, click long on its icon in the dock and select "Force Quit".

To delete the RSS feed, I resolved to tracking down the corresponding preferences file and I found this one:

~/Library/Preferences/com.apple.desktopscreensaver.rsspictures.plist

While System Preferences is closed, open the file in a text editor (I like TextWrangler) and delete the feed entry from the dictionary. My resulting file looked like this:




    
        rssPicSubscriptions
        
            com.apple.screensaver.rsspics
            
        
    

Save the file and reopen System Preferences to verify that the RSS screen save is no longer in the list. Done!

Update: I hear that you also can simply delete the file and you may need to restart or at least logout and login again.

Trying to update Xcode 4.0.1 from within the Mac AppStore application, I was greeted with this error message:

You have updates available for other accounts Sign in to (null) to update applications for that account.

There exist numerous forum entries on Apple's discussion board on that subject and the recommended solution is to trash the "Install Xcode" application and then to re-launch the AppStore, selecting to re-install Xcode.

I trashed "Install Xcode" but AppStore produced the same message. Relaunched one additional time and it allowed me to update (note: not install). However, when it was finished, there was no new "Install Xcode" in the Applications folder!

It turns out, the AppStore had located and updated a different copy of the software on a separate drive where I had made a backup, even though I had renamed it to "Install Xcode-4.0.1". Its info window revealed that it had been modified and that its version number now was 4.0.2.

Installation from that modified backup worked correctly.

The old backup could be restored from the version that I had put into the trash.

Compiling an application for the MacOX10.4u SDK (with Xcode 3.2.4, GCC 4.2.1) results in this linker warning:

ld: warning: object file compiled with -mlong-branch which is no longer needed. To remove this warning, recompile without -mlong-branch: /Developer/SDKs/MacOSX10.4u.sdk/usr/lib/crt1.o

This is not a critical issue and can be ignored. However, it can also be fixed as shown by an answer from Bernhard Baehr on lists.apple.com:

What needs to be done is to recompile the Csu package which can be found on Apple's opensource archive, e.g. the one for 10.4.11 x86 where the -mlong_branch flag has already been removed: http://www.opensource.apple.com/release/mac-os-x-10411x86 http://www.opensource.apple.com/tarballs/Csu/Csu-71.tar.gz

Then it's just a question of recompiling it:

cd ~/Downloads
tar zxvf Csu-71.tar.gz
cd Csu-71
make RC_ARCHS="ppc ppc64 i386 x86_64"

Then we can replace the (stripped) object file in the SDK:

cd /Developer/SDKs/MacOSX10.4u.sdk/usr/lib/
sudo mv crt1.o{,.org}
sudo strip -S ~/Downloads/Csu-71/crt1.o -o crt1.o
sudo chmod 644 crt1.o

On Mac OS X 10.5 (Leopard) it appears to work fine, but when I quit my app, on a machine running 10.4 (Tiger), these messages appear in the Console:

2009-03-03 21:49:10.680 MyApp[6793] *** Illegal NSTableView data source
    (). Must implement numberOfRowsInTableView: and
    tableView:objectValueForTableColumn:row:
2009-03-03 21:49:23.139 MyApp[6793] *** -[NSCFString count]:
    selector not recognized [self = 0x1bc7f00]
2009-03-03 21:49:23.140 MyApp[6793] Exception raised during posting
    of notification.  Ignored.  exception: *** -[NSCFString count]:
    selector not recognized [self = 0x1bc7f00]

The interesting fact is that the MyApp class is the delegate of the NSTableView since it implements support for drag & drop. However, it is not designed to be the data source for the NSTableView. Instead, I use an NSArrayController through a binding in the NSTableView instance. This works fine until one quits.

What I suspect is happening (on Tiger) is that the NSArrayController is purged before the NSApp, which suddely remains as the only data source of the NSTableView, but without the access methods implemented.

The solution would be to implement dummy methods in the MyApp class for numberOfRowsInTableView: and tableView:objectValueForTableColumn:row: where one returns 0 and nil, respectively.

Searched for it online and found this solution, which worked fine for me (Xcode 3.0):

defaults write com.apple.xcode  PBXCustomTemplateMacroDefinitions  \
        '{ ORGANIZATIONNAME = "tredje design"; }'

The goal is to access the preferences of a second application and to be able to change those preferences. I thus tried:

theDef = [[NSUserDefaults standardUserDefaults] retain];
[theDef addSuiteNamed:MyHelperAppDomain];

However, when a setting was changed and when I instruct the NSUserDefaults class to synchronize, the changes are not saved in the MyHelperAppDomain. This is because addSuiteNamed: only adds the settings from that domain; it does not change the domain!

How did I find the mistake? Tried this command in the Terminal:

> defaults find DateFormat
Found 1 keys in domain 'se.tredje.myapp': {DateFormat = "%+"; }
Found 1 keys in domain 'MyHelperApp': {DateFormat = "%F"; }

To change the preferences for a different application domain, I have found this alternative:

CFPreferencesSetAppValue( (CFStringRef) DefaultDateFormat,
    (CFStringRef) DefaultDateFormatDefault,
    (CFStringRef) MyHelperAppDomain );
CFPreferencesAppSynchronize( (CFStringRef) MyHelperAppDomain );

Encountering the above Xcode error when trying to build a Unit Test Bundle target usually means one of two things:

  • The SenTestingKit is not installed.
  • You are using an SDK with an older version of the Mac OS, where SenTestingKit is not included.

For the latter case, a possible solution is to set SDKROOT to "" (an empty string) for the testing target. Alternatively, one may add a link to the framework inside the /Developer/SDKs/<version>/System/Frameworks directory. However, trying that only triggered the next problem:

...MyApp: [NSBundle load] ... EXC_BAD_ACCESS (0x0001)KERN_INVALID_ADDRESS (0x0001) at 0xfffffffc /Developer/Tools/otest exited with error code 11 (it may have crashed)

It turns out that one should not try to run a unit test framework with settings other than ARCHS=$(native_arch), i.e. on a MacBook Pro, it should be "i386".

A follow-up problem is that one cannot test items with third-party libraries that do not support the same architecture (e.g. libeSellerateObjC.a, version 3.6.3, is only "ppc").

Use of dealloc

- Posted in macOS by

After spending a few days trying to figure out why my log file was not truncated correctly, I re-discovered a feature of the Objective-C runtime: The dealloc method is never called - at least not to my knowledge.

Therefore, do not add mission-critical code in the dealloc method of a class; use a dedicated custom method instead, for instance:

- (void) close
{
    [theLog truncateFileAtOffset:[theLog offsetInFile]];
    [theLog closeFile];
}

A not very well documented error message which occurs right at the beginning of the build, typically during compilation of the prefix file. The error is found in a derived file, for instance:

.../EnterMordor.build/DerivedSources/EnterMordor_vers.c:1: error: parse error before ';' token:

[...] const double EnterMordorVersionNumber __attribute__
((used)) = (double);

Observe that there is no valid argument after the equal sign. To find the cause, we must know that derived files are based on our build settings. In my case, the fault lies in the fact that the built setting VERSIONING_SYSTEM is set to apple-generic, but I was missing is a setting for the CURRENT_PROJECT_VERSION variable.

See also Xcode: Help -> Show Build Setting Notes -> Versioning.

According to Chris Hanson's article, the apple-generic versioning system uses agvtool to auto-update all Info.plist files. Also, there will be a TargetVersionString and a TargetVersionNumber variable available to your code. Right now, I you do not like or need all that, so I simply set the versioning system to "none" and continue to manually update the CFBundleShortVersionString and CFBundleVersion settings.