tag:blogger.com,1999:blog-69380845227631683302024-03-14T02:19:22.654-05:00IT Non-whizzosI search the Internet for answers to computer technical problems that I encounter. When the Internet does not supply me with an answer, I research one on my own. Then, I document the answer here so others can find it.
Also, for your benefit, this stupid blog name makes a great mnemonic.Unknownnoreply@blogger.comBlogger98125tag:blogger.com,1999:blog-6938084522763168330.post-66697149115689554182016-02-13T14:09:00.001-06:002016-02-13T14:15:08.806-06:00Very short – if not the shortest – Swift logging library.I'm just a lone dude making risky-dink iOS apps. I do not want or need a fancy logging library. Here is what I do <b><i>not</i></b> need:<br />
<br />
<ul>
<li>Colors.</li>
<li>Multiple channels.</li>
<li>Logging anywhere else other than standard output.</li>
<li>File rotation.</li>
<li>Complicated filters.</li>
<li>Helper functions that save me from typing 10 extra characters.</li>
<li>Verbosity.</li>
<li>Levels.</li>
<li>Formatters.</li>
<li>Thread safety.</li>
<li>Appenders.</li>
<li>XML anything.</li>
<li>Document Object Model hierarchies.</li>
<li>Targets.</li>
<li>Layouts.</li>
</ul>
<br />
I don't even need date and time information. That line prefix that <b>NSLog</b> kicks out? Too long! You know what I like column 1 of my log files to contain? The first character of my log message.<br />
<br />
So just use <span style="font-family: "courier new" , "courier" , monospace;">print()</span>, right? Well, the problem is, I throw all those print statements around, but I'm only debugging 1 or 2 entities at a time, and I don't want to look at all those print statements from 2 weeks ago confusing me while I debug something now.<br />
<br />
So the only feature I need is categories. I specify a category when I write the call to my logging function along with a message. Somewhere central, I can turn on or off what categories get logged.<br />
<br />
So my requirements are:<br />
<ul>
<li>Print the message I pass in.</li>
<li>Unless I don't want that message printed right now.</li>
</ul>
<br />
So anyway, here is my fancy logging library.
<br />
<div>
<pre>struct L {
// These are the only categories that will be logged. Adjust accordingly.
private static let categories = ["Pilot"]
typealias M = ((String) -> Void)
static let c:[String : M] = {
var tmp = [String : M]()
for s in L.categories {
tmp[s] = L.m
}
return tmp
}()
static func m(message:String) {
print(message)
}
}
</pre>
</div>
<div>
<br />
And here is how you use it.<br />
<br /></div>
<pre>class Pilot {
private let n = String(Pilot)
....
L.c[n]?("radians = \(radians)")
....
L.c["Err"]?("state was never set!")
}
class Location {
private let c = String(Location)
....
L.c[c]?("directionToLocation = \(directionToLocation)")
}
</pre>
<br />
Because <span style="font-family: "courier new" , "courier" , monospace;">categories</span> only has "Pilot", only the "radians" log line will get printed. I can chose to use the names of classes for the category or any string I want.<br />
<br />
When I'm ready to push to the App Store, I can leave <span style="font-family: "courier new" , "courier" , monospace;">categories</span> as "Err" to record any errors. As if I'll ever be able to talk a user through pulling and sending me their device console logs.<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6938084522763168330.post-46169073418213777172015-11-27T08:18:00.000-06:002015-11-27T08:18:22.946-06:00Trouble installing Perl module GitLab::API::v3 on OS X El Capitan (10.11.1)I hit this problem while writing <a href="http://it-nonwhizzos.blogspot.com/2015/11/perl-script-to-backup-gitlabcom-project.html">my own solution to backing up project issues on GitLab.com</a>.<br />
<br />
My script uses OS X El Capitan (10.11.1) system Perl.<br />
<br />
I installed GitLab::API::v3 Perl module, which is found at <a href="https://metacpan.org/pod/GitLab::API::v3">https://metacpan.org/pod/GitLab::API::v3</a><br />
<br />
This GitLab API Perl client is talked about here: <a href="https://about.gitlab.com/applications/#api-clients">https://about.gitlab.com/applications/#api-clients</a><br />
<br />
I used cpanm to pull down CPAN modules, and it is described here: <a href="http://www.cpan.org/modules/INSTALL.html">http://www.cpan.org/modules/INSTALL.html</a><br />
<br />
Preamble over, on to the problem.<br />
<br />
<strong>GitLab::API::v3</strong> uses <strong>Moose</strong>, but the version of <strong>Moose</strong> that comes with Perl 5.18.2 (OS X El Capitan system Perl) will not work with the version of <strong>Runtime</strong> which <strong>cpanm</strong> automatically pulls down to use in <strong>GitLab::API::v3</strong>. I noticed this in unit test failure from <strong>Type::Tiny</strong> <em>30-integration/Moo/inflation2.t</em>. So I pulled down a new <strong>Moose</strong> first.<br />
<br />
Here was my order of commands, as pulled from a combination of shell command history and my brain's recollection.<br />
<ol>
<li><tt>cpanm GitLab::API::v3</tt> (fails)</li>
<li><tt>cpanm TAP::Harness::Env</tt></li>
<li><tt>cpanm Const::Fast</tt> (fails)</li>
<li><tt>cpanm Type::Tiny</tt> (fails)</li>
<li><tt>cpanm Moose</tt></li>
<li><tt>cpanm GitLab::API::v3</tt></li>
</ol>
Here is what the error looked like in <em>build.log</em>:<br />
<br />
<pre>Invalid version format (version required) at /Users/jeff/perl5/lib/perl5/Module/Runtime.pm line 386.
BEGIN failed--compilation aborted at t/30-integration/Moo/inflation2.t line 49.
t/30-integration/Moo/inflation2.t .........................
Dubious, test returned 255 (wstat 65280, 0xff00)
No subtests run
[42 LINES LATER]
Test Summary Report
-------------------
t/30-integration/Moo/inflation2.t (Wstat: 65280 Tests: 0 Failed: 0)
Non-zero exit status: 255
Parse errors: No plan found in TAP output
Files=151, Tests=1666, 19 wallclock secs ( 0.68 usr 0.32 sys + 16.10 cusr 2.28 csys = 19.38 CPU)
Result: FAIL
Failed 1/151 test programs. 0/1666 subtests failed.
make: *** [test_dynamic] Error 255
-> FAIL Installing Type::Tiny failed. See /Users/jeff/.cpanm/work/1448136089.38532/build.log for details. Retry with --force to force install it.
</pre>
<br />
<br />
<br />Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-6938084522763168330.post-10726962889560323902015-11-26T18:23:00.001-06:002015-11-26T18:23:19.800-06:00Perl script to backup GitLab.com project issues.In using the GitLab.com hosting service, I could not find an archive button to download the issues for a project. If such functionality exists, it is well hidden from me.<br />
<br />
It does have a button to download a zip of the git repos itself, but I find this incredibly bizarre, since if I'm using GitLab as a git remote, that means I already have the repos.<br />
<br />
What I wrote is only meant to be a primitive last resort backup. To manually reenter all my issues from the saved output of this script would be a giant pain in the ass, but at least recovery would be <i>possible</i>. Before, if all my issues magically disappeared from GitLab.com, accurate restoration would be <i>impossible</i>.<br />
<br />
You'll have to install <a href="https://metacpan.org/pod/GitLab::API::v3">GitLab::API::v3 module</a>. Right now, it doesn't handle issue comments, I had to add the <tt>issue_comments</tt> method myself. See bottom of this post that.<br />
<br />
In any case, here is:<br />
<br />
<pre>use v5.18;
use warnings;
use strict;
use Data::Dumper;
use GitLab::API::v3;
use POSIX qw(strftime);
my $v3_api_url = 'http://gitlab.com/api/v3';
my $token = 'YeAhR1GhTkEePgUeSs1nG';
my $api = GitLab::API::v3->new(
url => $v3_api_url,
token => $token,
);
my $project_id_num = 123456;
say "Getting issues for project $project_id_num.";
my $all_issues = $api->paginator(
'issues',
$project_id_num,
)->all();
my $backup_root = '/Users/jeff/VGT/GitLab backup/';
my $now_string = strftime("%Y-%m-%d_%H-%M-%S", localtime);
my $backup_dir = $backup_root . $now_string;
mkdir $backup_dir or die "Fail to mkdir $backup_dir";
my $issues_out = $backup_dir . '/issues.dump';
say "Logging issues.";
open (my $issues_fh, '>', $issues_out) or die "Cannot open $issues_out";
print $issues_fh Dumper($all_issues);
close $issues_fh;
say "Getting comments.";
for my $issue_ref (@$all_issues) {
my $issue_id = $issue_ref->{'id'};
my $iid = $issue_ref->{'iid'};
my $comments = $api->issue_comments($project_id_num, $issue_id);
next if scalar(@$comments) == 0;
say "Logging comments for $iid.";
my $comment_dir = $backup_dir . '/' . $iid;
mkdir $comment_dir or die "Fail to mkdir $comment_dir";
my $comment_out = $comment_dir . '/comments.dump';
open my $comment_fh, '>', $comment_out or die "Cannot open $comment_out";
print $comment_fh Dumper($comments);
close $comment_fh;
}
say "Logging labels.";
my $labels = $api->labels($project_id_num);
my $labels_out = $backup_dir . '/labels.dump';
open my $labels_fh, '>', $labels_out or die "Cannot open $labels_out";
print $labels_fh Dumper($labels);
close $labels_fh;
exit 0;
</pre>
<br />
<br />
This is what I added to wherever-your-library-is/GitLab/API/v3.pm. Here is <tt>git diff</tt> output:
<br />
<br />
<pre>$ git diff 1c3c02b64f3a3c608891bc3021a002892b96958e v3.pm
diff --git a/v3.pm b/v3.pm
index bd745c0..b8effea 100644
--- a/v3.pm
+++ b/v3.pm
@@ -1866,6 +1866,27 @@ sub edit_issue {
return $self->put( $path, ( defined($params) ? $params : () ) );
}
+=head2 issue_comments
+
+ my $comments = $api->issue_comments(
+ $project_id,
+ $issue_id,
+ );
+
+ Sends a Clt;GET> request to Clt;/projects/:project_id/issues/:issue_id/notes> and returns the decoded/deserialized response body.
+
+=cut
+
+sub issue_comments {
+ my $self = shift;
+ croak 'issue_comments must be called with 2 arguments' if @_ != 2;
+ croak 'The #1 argument ($project_id) to issue_comments must be a scalar' if ref($_[0]) or (!defined $_[0]);
+ croak 'The #2 argument ($$issue_id) to issue_comments must be a scalar' if ref($_[1]) or (!defined $_[1]);
+ my $path = sprintf('/projects/%s/issues/%s/notes', (map { uri_escape($_) } @_));
+ $log->infof( 'Making %s request against %s with params %s.', 'GET', $path, undef );
+ return $self->get( $path );
+}
+
=head1 LABEL METHODS
See L<http://doc.gitlab.com/ce/api/labels.html>.
</pre>
<br />
And that's it!
<br />
<br />Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-6938084522763168330.post-30691211654254644232015-07-26T19:38:00.004-05:002015-07-26T20:08:46.908-05:00JSTalk script for Acorn, crunching images for iOSSo it was time to crunch images for inclusion in an iOS app again. Because I ditched GIMP and moved to <a href="http://flyingmeat.com/">Acorn</a>, I can't reuse <a href="http://it-nonwhizzos.blogspot.com/2014/10/gimp-script-scheme-to-scale-multiple.html">my old Scheme script</a>.<br />
<br />
I had to use <a href="http://jstalk.org/">JSTalk</a> instead. It is by the same dude that wrote Acorn. It is basically a JavaScript wrapper to Core Foundation.<br />
<br />
I decided on JSTalk over AppleScript after glancing at the AppleScript syntax for about 5 seconds. I heard about JSTalk from the <a href="http://flyingmeat.com/acorn/docs/scripting.html">Acorn scripting docs</a>.<br />
<br />
Anyway, I had finished editing my "@2" images manually, and I needed the half-size image files. I had them all in one directory.<br />
<br />
I ran this script straight from the JSTalk Editor.<br />
<pre><code>
var acorn = JSTalk.application("Acorn");
var dirPath = @"/Users/jeff/VGT/art/vegetable photos/Working Temp/";
var fileManager = [[NSFileManager alloc] init];
var dirEnum = [fileManager enumeratorAtPath:dirPath];
var fileName = [dirEnum nextObject];
while (fileName) {
NSLog(fileName);
var range = [fileName rangeOfString:@"@2.jpg"];
if (range.location == NSNotFound) {
continue;
}
var fullPathFileName = dirPath + fileName;
NSLog(fullPathFileName);
var doc = acorn.open_(fullPathFileName);
var size = doc.canvasSize()
var newWidth = size.width / 2;
doc.scaleImageToWidth(newWidth);
var endIndex = [fileName length] - 6;
// How do I stringify this number so I can pass it to NSLog?
// NSLog(endIndex);
var modFileName = [fileName substringToIndex:endIndex];
NSLog(modFileName);
var modFullPathFileName = dirPath + modFileName + ".jpg";
NSLog(modFullPathFileName);
doc.dataRepresentationOfType("public.png").writeToFile(modFullPathFileName);
doc.close();
fileName = [dirEnum nextObject];
}
</code>
</pre>
Some problems I encountered:<br />
<ul>
<li>I could only pass 1 parameter to <tt>NSLog</tt>. The string format specifiers (<tt>%s</tt> and <tt>%@</tt>) just got lost.</li>
<li>I could not do <tt>while ((fileName = [dirEnum nextObject]))</tt>. It just couldn't understand that.</li>
<li>The class method <tt>[NSFileManaged defaultManager]</tt> did not work, so I had to init my own. I'm not sure if that is a JSTalk problem or because I've never written an OS X app before and that is normal.</li>
</ul>
Ug! A buddy just showed me the <i>JavaScript for Automation</i> video from WWCD 2014. I'm so far behind the tech curve, as usual.<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6938084522763168330.post-44988828736005828702015-07-12T10:49:00.000-05:002015-07-12T10:49:58.323-05:00Perl one-liner: files in this directory also in that directory?It's been too long since I've used Perl. But anyway...<br />
<br />
<b>Problem:</b> I copied files from one folder to another folder manually. Are any files missing?<br />
<br />
In the below example "." is the single source folder and "../vegetables.xcassets" is the parent folder of various destination folders.<br />
<pre><code>
perl -e 'opendir(D,".");@f=grep{/jpg$/}readdir(D);for $i (@f){@g = glob qq("../vegetables.xcassets/*/$i"); $m="Not $i"; if (-f $g[0]) {$m="OK"}; print "$m $g[0]\n";}'
</code></pre>
<br />
Sample output:<br />
<pre><code>
OK ../vegetables.xcassets/oregano_large.imageset/oregano_large.jpg
Not oregano_large@2x.jpg
OK ../vegetables.xcassets/oregano_small.imageset/oregano_small.jpg
OK ../vegetables.xcassets/oregano_small.imageset/oregano_small@2x.jpg</code>
</pre>
<br />
Here you can see I forgot to copy oregano_large@2x.jpg.
<br />
<br />
I used Perl because I forgot how awful shell handles spaces in file names, and I tried to do it that way first. I realize my example output does not contain spaces in the file names, but you don't want to see the listing all the way down to "summer squash".<br />
<br />
If you are asking why did I not automate the copy of the files, it is because the copy happened with Xcode, and I needed its internal XML configuration mangling to happen at the same time.Jefferyhttp://www.blogger.com/profile/14948861488878036693noreply@blogger.com0tag:blogger.com,1999:blog-6938084522763168330.post-22554131047648195222015-04-04T11:39:00.003-05:002015-04-05T16:24:18.334-05:00Viewing exception in lldbIt has been a while since I wrote one of these. Time to do it again.<br />
<br />
My app aborted on an assertion.<br />
<br />
I had the "All Exceptions" breakpoint enabled.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-OPion-aCmAE/VSARM0bMSMI/AAAAAAAACKo/ztgi_KeBex4/s1600/Screen%2BShot%2B2015-04-04%2Bat%2B11.27.58%2BAM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-OPion-aCmAE/VSARM0bMSMI/AAAAAAAACKo/ztgi_KeBex4/s1600/Screen%2BShot%2B2015-04-04%2Bat%2B11.27.58%2BAM.png" /></a></div>
<br />
I got this line in Xcode console.<br />
<pre>*** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-3318.93/UITableView.m:1314</pre>
In the Debug navigator, I click on the <i>objc_exception_throw</i> frame.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-J06QFmBIiAg/VSASDflZ6PI/AAAAAAAACKw/yuH283-ImlY/s1600/Screen%2BShot%2B2015-04-04%2Bat%2B11.30.45%2BAM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-J06QFmBIiAg/VSASDflZ6PI/AAAAAAAACKw/yuH283-ImlY/s1600/Screen%2BShot%2B2015-04-04%2Bat%2B11.30.45%2BAM.png" /></a></div>
<br />
In the Console of the Debug area, I type in:<br />
<pre>expr -o -- $eax</pre>
And this tells me exactly what my problem is.
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-yJoR9g-Uuo4/VSASoKoGbsI/AAAAAAAACK8/KmmOPIVnzh4/s1600/Screen%2BShot%2B2015-04-04%2Bat%2B11.34.12%2BAM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-yJoR9g-Uuo4/VSASoKoGbsI/AAAAAAAACK8/KmmOPIVnzh4/s1600/Screen%2BShot%2B2015-04-04%2Bat%2B11.34.12%2BAM.png" /></a></div>
<br />
<b>Note:</b> the <tt>$eax</tt> only works in the Simulator. When debugging on an actual device use <tt>$r0</tt>.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6938084522763168330.post-82977502411555029942015-03-02T06:54:00.004-06:002015-03-02T06:54:31.079-06:00Object-oriented State pattern with view controllers in Objective-C and iOSI have a UIViewController subclass that is controlling a view hierarchy which represents a portion of the UI. That portion of the UI can be in one of three modes: browse, edit, or empty. These modes can change back and forth at run time by user actions.<br />
<br />
Right now I have code in every method of the view controller that looks like this:<br />
<pre><code>
NSAssert(self.mode == SBModeBrowse || self.mode == SBModeEmpty, @"Should not be called in SBMode %d", self.mode);
</code>
</pre>
And this:
<br />
<pre><code>
if (self.mode != SBModeEmpty)
{
[self performScrollCompletion];
}
</code>
</pre>
And so on.<br />
<br />
Even worse, I'm probably missing a few <i>asserts</i> and <i>if-thens</i>, and the code just happens to work at the moment.<br />
<br />
It seems the object-oriented pattern that solves this situation is <a href="http://sourcemaking.com/design_patterns/state">the State pattern</a>.<br />
<br />
It took me a while to figure out how to do this with UIViewController subclasses because the state behavior will affect UIControls wired up via IBOutlets to the view controller itself. How are the behavior classes supposed to manipulate these objects?<br />
<br />
Also, I did not read the State pattern explanation closely enough, so I started off trying to subclass my view controller subclasses instead of merely adding a property to them for a behavior object.<br />
<br />
I made a simple sandbox project to teach myself how to add the State pattern to view controllers. Here is my specification.<br />
<ul>
<li>Display a UILabel with a number.</li>
<li>Display a UIButton.</li>
<li>Display a UIStepper.</li>
<li>Start in Browse mode.</li>
<li>In Browse mode:</li>
<ul>
<li>Only button allows user taps.</li>
<li>Only label and button showing.</li>
<li>Button title is "Edit" and tapping it goes to Edit mode.</li>
<li>Stepper is invisible and does not allow taps.</li>
</ul>
<li>In Edit Mode:</li>
<ul>
<li>Stepper is visible and allows taps.</li>
<li>Stepper adjusts number in label.</li>
<li>Button title is "Browse" and tapping it does to Browse mode.</li>
</ul>
<li>When exiting Edit mode, if the number in the label is less than 1, then enter Empty mode.</li>
<li>In Empty Mode:</li>
<ul>
<li>Stepper is invisible and no taps allowed.</li>
<li>Label background is red.</li>
<li>Button tap moves to Edit mode.</li>
</ul>
</ul>
Here are the classes and code to accomplish this by using the State pattern and view controllers.<br />
<br />
<h4>
InfoKeys.h</h4>
<pre><code>
#ifndef SandBox3_InfoKeys_h
#define SandBox3_InfoKeys_h
static NSString *const keyButton = @"button";
static NSString *const keyStepper = @"stepper";
static NSString *const keyLabel = @"label";
#endif
</code>
</pre>
<h4>
ViewControlller.h</h4>
<pre><code>
@class Behavior;
@interface ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UIButton *button;
@property (weak, nonatomic) IBOutlet UILabel *label;
@property (weak, nonatomic) IBOutlet UIStepper *stepper;
@property (strong, nonatomic) Behavior *behavior;
@property (assign, nonatomic) uint16_t labelValue;
- (IBAction)buttonTapped:(id)sender;
- (IBAction)stepperTapped:(id)sender;
@end
</code>
</pre>
<h4>
ViewController.m</h4>
<pre><code>
#import "ViewController.h"
#import "Behavior.h"
#import "InfoKeys.h"
@implementation ViewController
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.behavior = [[Behavior alloc] initWithInfo:@{keyButton: self.button, keyLabel: self.label, keyStepper: self.stepper}];
}
- (IBAction)buttonTapped:(id)sender
{
[self.behavior buttonTapped:@{keyButton: sender, keyStepper: self.stepper, keyLabel: self.label}];
}
- (IBAction)stepperTapped:(id)sender
{
[self.behavior stepperTapped:@{keyStepper: sender, keyLabel: self.label}];
}
@end
</code>
</pre>
<h4>
Behavior.h</h4>
<pre><code>
@interface Behavior : NSObject
- (instancetype)initWithInfo:(NSDictionary *)info;
- (void)buttonTapped:(NSDictionary *)info;
- (void)stepperTapped:(NSDictionary *)info;
@end
</code>
</pre>
<h4>
Behavior.m</h4>
<pre><code>
#import "Behavior.h"
#import "BehaviorBrowse.h"
#import "BehaviorEdit.h"
#import "BehaviorEmpty.h"
#import "InfoKeys.h"
@implementation Behavior {
Behavior *_mode;
}
- (instancetype)initWithInfo:(NSDictionary *)info
{
self = [super init];
if (self) {
// Prevent problems if subclasses call this method (for example, as super in overrides).
if ([self isMemberOfClass:[Behavior class]]) {
_mode = [[BehaviorBrowse alloc] initWithInfo:info];
}
}
return self;
}
- (void)buttonTapped:(NSDictionary *)info
{
[_mode buttonTapped:info];
UIStepper *stepper = info[keyStepper];
// Coming back from Empty should allow mode to go to Edit so user can increase 0 value.
if (stepper.value < 1 && ![_mode isKindOfClass:[BehaviorEmpty class]]) {
_mode = [[BehaviorEmpty alloc] initWithInfo:info];
}
else {
if ([_mode isKindOfClass:[BehaviorEdit class]]) {
_mode = [[BehaviorBrowse alloc] init];
}
else { // Coming from Empty ends up here also.
_mode = [[BehaviorEdit alloc] init];
}
}
}
- (void)stepperTapped:(NSDictionary *)info
{
[_mode stepperTapped:info];
}
@end
</code>
</pre>
<h4>
BehaviorBrowse.m</h4>
<pre><code>
#import "BehaviorBrowse.h"
#import "InfoKeys.h"
@implementation BehaviorBrowse
- (instancetype)initWithInfo:(NSDictionary *)info
{
self = [super init];
if (self) {
UIButton *button = info[keyButton];
UILabel *label = info[keyLabel];
UIStepper *stepper = info[keyStepper];
label.text = [NSString stringWithFormat:@"%.0f", stepper.value];
stepper.alpha = 0.0;
stepper.userInteractionEnabled = NO;
// Button title shows user way to go to opposite mode.
[button setTitle:@"Edit" forState:UIControlStateNormal];
}
return self;
}
- (void)buttonTapped:(NSDictionary *)info
{
UIButton *button = (UIButton *)info[keyButton];
// Button titles inform user of way back to the mode they are about to leave.
[button setTitle:@"Browse" forState:UIControlStateNormal];
UIStepper *stepper = (UIStepper *)info[keyStepper];
[UIView animateWithDuration:0.3
animations:^(void){stepper.alpha = 1.0;}
completion:^(BOOL finished) {stepper.userInteractionEnabled = YES;}];
}
- (void)stepperTapped:(NSDictionary *)info
{
NSAssert(NO, @"Stepper should not be tapable during browse mode.");
}
@end
</code>
</pre>
<h4>
BehaviorEdit.m</h4>
<pre><code>
#import "BehaviorEdit.h"
#import "InfoKeys.h"
@implementation BehaviorEdit
- (void)buttonTapped:(NSDictionary *)info
{
UIStepper *stepper = info[keyStepper];
UIButton *button = info[keyButton];
stepper.userInteractionEnabled = NO;
// Let user know that button can bring them back to Edit from whatever mode comes next.
[button setTitle:@"Edit" forState:UIControlStateNormal];
[UIView animateWithDuration:0.3 animations:^(void){stepper.alpha = 0.0;}];
}
- (void)stepperTapped:(NSDictionary *)info
{
UILabel *label = info[keyLabel];
UIStepper *stepper = info[keyStepper];
label.text = [NSString stringWithFormat:@"%.0f", stepper.value];
}
@end
</code>
</pre>
<h4>
BehaviorEmpty.m</h4>
<pre><code>
#import "BehaviorEmpty.h"
#import "InfoKeys.h"
@implementation BehaviorEmpty
- (instancetype)initWithInfo:(NSDictionary *)info
{
self = [super init];
if (self) {
UILabel *label = info[keyLabel];
label.backgroundColor = [UIColor redColor];
UIStepper *stepper = info[keyStepper];
stepper.alpha = 0.0;
stepper.userInteractionEnabled = NO;
}
return self;
}
- (void)buttonTapped:(NSDictionary *)info
{
UIStepper *stepper = info[keyStepper];
UIButton *button = info[keyButton];
[button setTitle:@"Browse" forState:UIControlStateNormal];
UILabel *label = info[keyLabel];
label.backgroundColor = [UIColor lightGrayColor];
[UIView animateWithDuration:0.3
animations:^(void){stepper.alpha = 1.0;}
completion:^(BOOL finished) {stepper.userInteractionEnabled = YES;}];
}
- (void)stepperTapped:(NSDictionary *)info
{
NSAssert(NO, @"Stepper should not be tapable during empty mode.");
}
</code>
</pre>
<br />
I am always interested in hearing better ways to do this.
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6938084522763168330.post-52257015439225195472015-02-08T20:48:00.001-06:002015-02-10T20:32:02.017-06:00The Schwartzian Transform (from Perl) in Swift.I realize that the "Schwartzian Transform" is not the name of algorithm itself but rather the name of the compact idiom in Perl for the expression of the algorithm. Since Swift has all of <tt>split()</tt>, <tt>join()</tt>, and <tt>map()</tt>, I will attempt to not only duplicate the algorithm, but the idiom itself.<br />
<br />
As I write this, I am not certain I will succeed. I'm kind of excited. It is like a stage magic show.<br />
<br />
I'm going off the <a href="http://www.stonehenge.com/merlyn/UnixReview/col64.html">2006 article</a> from Randal's web site.<br />
<br />
Let's do the steps all broken down.<br />
<br />
<pre><code>let data = "Bob 10\nSue 7\nJane 12\nBill 10\nJim 1\nNancy 8\n"
let lines = split(data, {$0 == "\n"})
let annotatedLines: Array = map(lines, {[$0, split($0, {$0 == " "})[1]]})
let sortedLines = sorted(annotatedLines, {$0[1] < $1[1]})
let cleanLines = map(sortedLines, {$0[0]})
let result: String = join("\n", cleanLines)
println(result)
</code>
</pre>
Here is what it looks like with <tt>println()</tt> statements in a playground.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-gfmt7DYoVEs/VNgb5BIpkKI/AAAAAAAACHI/Ubbelszy-nA/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B8.30.21%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-gfmt7DYoVEs/VNgb5BIpkKI/AAAAAAAACHI/Ubbelszy-nA/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B8.30.21%2BPM.png" /></a></div>
<br />
And here it is condensed properly to match the compact Perl idiom.<br />
<pre><code>
let data = "Bob 10\nSue 7\nJane 12\nBill 10\nJim 1\nNancy 8\n"
let result2 = join("\n",
map(
sorted(
map(
split(data, {$0 == "\n"}),
{[$0, split($0, {$0 == " "})[1]]}),
{$0[1] < $1[1]}),
{$0[0]}))
println(result2)
</code>
</pre>
And in the playground to prove it works.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-8qX8OqxnWrY/VNgbM2nPQTI/AAAAAAAACHA/eEOMP4NMsOo/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B8.27.37%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-8qX8OqxnWrY/VNgbM2nPQTI/AAAAAAAACHA/eEOMP4NMsOo/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B8.27.37%2BPM.png" /></a></div>
<br />
Just so you know, as Xcode ran this code in the playground, my MacBook Pro (15-inch, Late 2011) CPU fans kicked in. I'm pretty sure Perl would not cause that to happen while processing the same data set.<br />
<br />
Now, you may be thinking to yourself, "But it didn't work! Ten is not less than seven!" Yes, that is an obvious machine collating sequence problem because my version is doing string comparisons and not numeric.<br />
<br />
This is where I think I've found a Swift defect. I can do this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-IcxpQ25ET-M/VNgdk9GEIQI/AAAAAAAACHU/w5bfb2WDmuQ/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B8.37.50%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-IcxpQ25ET-M/VNgdk9GEIQI/AAAAAAAACHU/w5bfb2WDmuQ/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B8.37.50%2BPM.png" /></a></div>
<pre><code>
let stuff = "xxx 13"
let num:Int! = split(stuff, {$0==" "})[1].toInt()
println("num = \(num)")
</code>
</pre>
But when I try to tack <tt>toInt()</tt> inside <tt>map()</tt> for <i>annotatedLines</i>, I get an error.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-WdL64KFPjJk/VNge134zBzI/AAAAAAAACHg/sU7VFLpFI0A/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B8.42.57%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-WdL64KFPjJk/VNge134zBzI/AAAAAAAACHg/sU7VFLpFI0A/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B8.42.57%2BPM.png" /></a></div>
<br />
So the summary is that the Perl code is easier to read, it probably doesn't cause my CPU fans to engage, and its flexible <i>scalar</i> type is more convenient than the old integer vs string separation.<br />
<br />
<b>Up Next:</b> the Orcish Maneuver.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6938084522763168330.post-66710812798102803002015-02-08T10:36:00.000-06:002015-02-08T10:36:01.064-06:00Xcode build script: Change value in non-compiled file between Debug and Release.I have a file that contains lines of text. One of those lines should to have a different value between <i>Debug</i> and <i>Release</i>. The file is not handled by the C preprocessor.<br />
<br />
I am accomplishing this with an Xcode build script. If you know of something better, please tell me.<br />
<br />
Here is the file and its contents.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-Vsp_Jxjo1_g/VNd1pkkD7tI/AAAAAAAACFU/BjwPXy24ZRc/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B8.38.30%2BAM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-Vsp_Jxjo1_g/VNd1pkkD7tI/AAAAAAAACFU/BjwPXy24ZRc/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B8.38.30%2BAM.png" /></a></div>
<br />
I want the string "Production" for <i>thing1</i> to be replaced with "Debug" during development. In my particular situation, if the script fails, it is better that the release value is used during development instead of the debug value escaping into the app store. Therefore, I use the "Production" string as the default value.<br />
<br />
Look at Project | Target | <i>Build Phases</i> | <i>Copy Bundle Sources</i>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-Yv96LXpm6QY/VNd9EJLiuNI/AAAAAAAACFk/7B-pDSeqKwA/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B9.12.49%2BAM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-Yv96LXpm6QY/VNd9EJLiuNI/AAAAAAAACFk/7B-pDSeqKwA/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B9.12.49%2BAM.png" /></a></div>
<br />
I create a new build phase after this one. Select <i><b>+</b> button</i> (tooltip: Add New Build Phase tool) | <i>New Run Script Phase</i>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-aZdk2GxxpHM/VNd98HDDGfI/AAAAAAAACFs/6PuK8Lhpek0/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B9.15.59%2BAM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-aZdk2GxxpHM/VNd98HDDGfI/AAAAAAAACFs/6PuK8Lhpek0/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B9.15.59%2BAM.png" height="232" width="320" /></a></div>
<div>
<br /></div>
<div>
Put the <i>Run Script</i> after <i>Copy Bundle Resources</i>.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-7muQqsxyyZU/VNd-TUghgvI/AAAAAAAACF0/4NSe7UigULQ/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B9.18.07%2BAM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-7muQqsxyyZU/VNd-TUghgvI/AAAAAAAACF0/4NSe7UigULQ/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B9.18.07%2BAM.png" /></a></div>
<br />
The next step unfortunately involves intimate knowledge of shell syntax. To create your own scripts to do different things, you will also be digging around in the <a href="https://developer.apple.com/library/ios/documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html">Build Setting Reference</a> doc.<br />
<br />
Here is the script that does my task relatively safely.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/---XmKbdxt6g/VNeL95ap90I/AAAAAAAACGE/gfPwHN_iBqE/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B10.16.21%2BAM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/---XmKbdxt6g/VNeL95ap90I/AAAAAAAACGE/gfPwHN_iBqE/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B10.16.21%2BAM.png" /></a></div>
<br />
I doubt anyone wants to cut and paste that, but just in case:<br />
<br />
<pre><code>echo "CONFIGURATION = $CONFIGURATION"
if [ "$CONFIGURATION" == "Debug" ]; then
f1="Statham.notJson"
echo "CONFIGURATION_BUILD_DIR = $CONFIGURATION_BUILD_DIR"
echo "CONTENTS_FOLDER_PATH = $CONTENTS_FOLDER_PATH"
f2="$CONFIGURATION_BUILD_DIR/$CONTENTS_FOLDER_PATH/$f1"
if [ -f $f2 ]; then
sed -i "" -e '/thing1:/s/Production/Debug/' "$f2"
else
echo "File not found: $f2"
fi
else
echo "CONFIGURATION is not Debug. Not updating $f1."
fi
</code>
</pre>
I like the echoes in that script because they help to debug it by looking at the build logs.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-5BHMQfv_SCU/VNeNV8wtqEI/AAAAAAAACGQ/3UpGEdwBgk8/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B10.22.16%2BAM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-5BHMQfv_SCU/VNeNV8wtqEI/AAAAAAAACGQ/3UpGEdwBgk8/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B10.22.16%2BAM.png" height="100" width="640" /></a></div>
<br />
Here is my Terminal output to test that my changes worked.<br />
<pre><code>
$ pwd
/Users/jeff/Library/Developer/Xcode/DerivedData/SandBox2-aiqtaeeaiietgzagreaqpyganmtt/Build/Products/Debug-iphonesimulator/Pen1.app
$ ls -l
total 72
drwxr-xr-x 6 jeff staff 204 Feb 8 10:11 Base.lproj
-rw-r--r-- 1 jeff staff 920 Feb 8 10:11 Info.plist
-rwxr-xr-x 1 jeff staff 21240 Feb 8 10:11 Pen1
-rw-r--r-- 1 jeff staff 8 Feb 8 10:11 PkgInfo
-rw-r--r-- 1 jeff staff 67 Feb 8 10:11 Statham.notJson
$ cat Statham.notJson
# Whatever file.
thing0: 76
thing1: "Debug"
oddItem: tulip
</code></pre>
<br />
Of course, my build settings were <i>Debug</i> at the time. Here is my scheme to prove it.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-GVin9B_iuRs/VNeN8EXbHSI/AAAAAAAACGY/xLSH8GxRqsA/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B10.24.36%2BAM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-GVin9B_iuRs/VNeN8EXbHSI/AAAAAAAACGY/xLSH8GxRqsA/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B10.24.36%2BAM.png" /></a></div>
<br />
Let's make sure the changes do <b>not</b> happen if we are building for <i>Release</i>. I update my scheme and build again. The first thing I notice is a difference in the build logs.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-bO7NT5VW7BY/VNeOmvCSoVI/AAAAAAAACGk/KzYuO8QbqDA/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B10.26.46%2BAM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-bO7NT5VW7BY/VNeOmvCSoVI/AAAAAAAACGk/KzYuO8QbqDA/s1600/Screen%2BShot%2B2015-02-08%2Bat%2B10.26.46%2BAM.png" /></a></div>
<br />
That looks good, but let's check for real, but be sure I'm in the right directory when I look.<br />
<br />
<pre><code>$ pwd
/Users/jeff/Library/Developer/Xcode/DerivedData/SandBox2-aiqtaeeaiietgzagreaqpyganmtt/Build/Products
$ ls -l
total 0
drwxr-xr-x 4 jeff staff 136 Feb 7 16:16 Debug-iphoneos
drwxr-xr-x 7 jeff staff 238 Feb 8 10:11 Debug-iphonesimulator
drwxr-xr-x 6 jeff staff 204 Feb 8 10:26 Release-iphonesimulator
$ cat Release-iphonesimulator/Pen1.app/Statham.notJson
# Whatever file.
thing0: 76
thing1: "Production"
oddItem: tulip
</code>
</pre>
It worked!<br />
<br />
Now, who can spot the (fairly harmless) defect in my shell script?<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6938084522763168330.post-27632387614323104662015-02-07T17:49:00.000-06:002015-02-08T07:19:45.764-06:00How to embed private Objective-C framework into iOS app on Xcode 6.I'm creating this post since <a href="https://developer.apple.com/library/ios/documentation/MacOSX/Conceptual/BPFrameworks/Tasks/CreatingFrameworks.html">Apple's documentation</a> on this topic is an out-of-date lie that mentions Xcode 2.4. And Stack Overflow is overrun with point collectors who can only answer minor variations of the same question over and over again.<br />
<div>
<br /></div>
<div>
The simplest form of this recipe is easy once you get past a few snags. I hope this helps someone some day before it also falls out of date.<br />
<br />
<span style="color: red;">Warning</span>: this only works for iOS 8 or better. I'm not sure the linker should seg fault because of this though.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-iBPzkLkoFDQ/VNaezQxxRII/AAAAAAAACE0/ygkuRvhXY0g/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B5.24.18%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-iBPzkLkoFDQ/VNaezQxxRII/AAAAAAAACE0/ygkuRvhXY0g/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B5.24.18%2BPM.png" height="110" width="640" /></a></div>
<br /></div>
<div>
I start with a project named <b>Pen1</b> in a workspace named <b>SandBox2</b>.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-jBqbZDEsDLU/VNZpzaXKExI/AAAAAAAACBs/cRuG-xJuR5g/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B1.38.18%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-jBqbZDEsDLU/VNZpzaXKExI/AAAAAAAACBs/cRuG-xJuR5g/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B1.38.18%2BPM.png" /></a></div>
<div>
<br /></div>
<div>
Elsewhere, I have already created a Cocoa Touch Framework like this.<br />
<br /></div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-kKAnY30rrFY/VNZsvM8BSyI/AAAAAAAACCA/H1goxQ1P7JM/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B7.58.33%2BAM%2Bcopy.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-kKAnY30rrFY/VNZsvM8BSyI/AAAAAAAACCA/H1goxQ1P7JM/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B7.58.33%2BAM%2Bcopy.png" /></a></div>
<br /></div>
<div>
The framework is a separate project from the <b>SandBox2</b> workspace. I did this to simulate the scenario of:<br />
<br />
<ul>
<li>You created some code in one project.</li>
<li>You have to add the code to another project.</li>
<li>You thought to yourself, "I'll turn this small chunk of code into a framework."</li>
<li>So then you create a separate project to house the framework with the idea of adding it into other projects and workspaces later.</li>
</ul>
<br />
<br />
The framework is named <b>BobLib</b>. It consists of 3 main files: <i>BobLib.h</i>, <i>Newhart.h</i>, and <i>Newhart.m</i>. Here are the contents of those files.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-H-Pk6grfTN4/VNZ4t4r5TcI/AAAAAAAACCY/t5PMZFcBFmA/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B2.41.11%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-H-Pk6grfTN4/VNZ4t4r5TcI/AAAAAAAACCY/t5PMZFcBFmA/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B2.41.11%2BPM.png" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-R4WhUyhSmWg/VNZ4wIQOBzI/AAAAAAAACCg/cBQopxNsEEw/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B2.41.31%2BPM.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-R4WhUyhSmWg/VNZ4wIQOBzI/AAAAAAAACCg/cBQopxNsEEw/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B2.41.31%2BPM.png" /></a><a href="http://3.bp.blogspot.com/-dmk6cYPs_b8/VNZ4rPFebcI/AAAAAAAACCQ/4LJ7PjQGMAU/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B2.41.43%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-dmk6cYPs_b8/VNZ4rPFebcI/AAAAAAAACCQ/4LJ7PjQGMAU/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B2.41.43%2BPM.png" /></a></div>
<br />
I want to use the method <span style="font-family: Courier New, Courier, monospace;">doThatThing</span> from the <span style="font-family: Courier New, Courier, monospace;">Newhart</span> class in my <b>Pen1</b> project.<br />
<br />
Next is something you <i>must</i> do, and I've only ever seen it mentioned in a WWDC 2014 video. You must select the <i>Newhart.h</i> file in the Project Navigator. Then in the Utilities Area, select the File Inspector. Inside the Target Membership section, you will have to change the value from "Project" to "Public".<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-MVJXVASkHbM/VNZ61DySUWI/AAAAAAAACCs/DrcqNNei-n0/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B2.50.18%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-MVJXVASkHbM/VNZ61DySUWI/AAAAAAAACCs/DrcqNNei-n0/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B2.50.18%2BPM.png" /></a></div>
<br />
If you don't do this, then after you add <b>BobLib</b> to <b>Pen1</b>, the compile of <b>Pen1</b> will fail because it can't find <i>Newhart.h</i>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-bVrDP-LSqTc/VNaqAFlOQvI/AAAAAAAACFE/q7qj2YmlRD8/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B6.11.28%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-bVrDP-LSqTc/VNaqAFlOQvI/AAAAAAAACFE/q7qj2YmlRD8/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B6.11.28%2BPM.png" /></a></div>
<br />
<br />
I build <b>BobLib</b> for both simulator and device. After the build, wait for Xcode to index files, and then <i>BobLib.framework</i> in the Project Navigator under <i>Products</i> group will turn from red text (not found, I suppose) to black text. Control-click <i>BobLib.framework</i> and select <i>Show in Finder</i> from the menu.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-JDtuOas6VLA/VNZ_rnBdAvI/AAAAAAAACC8/4SFce5hIrm0/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B3.10.29%2BPM%2Bcopy.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-JDtuOas6VLA/VNZ_rnBdAvI/AAAAAAAACC8/4SFce5hIrm0/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B3.10.29%2BPM%2Bcopy.png" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-ig3VQziiM1Q/VNZ_wzNjM8I/AAAAAAAACDE/YYd-Ue9VUIU/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B3.09.15%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-ig3VQziiM1Q/VNZ_wzNjM8I/AAAAAAAACDE/YYd-Ue9VUIU/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B3.09.15%2BPM.png" /></a></div>
<br />
I open <b>SandBox2</b> in Xcode. I drag the simulator build of <i>BobLib.framework</i> in Finder into <b>Pen1</b> in Xcode.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-A8Ee96qn36c/VNaDhXRkVHI/AAAAAAAACDQ/nC8eVZhoNSU/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B3.27.16%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-A8Ee96qn36c/VNaDhXRkVHI/AAAAAAAACDQ/nC8eVZhoNSU/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B3.27.16%2BPM.png" /></a></div>
<br />
I guess the options to select here are based on what you are doing with your source code control system. I have not worked out the best thing to do for my own environment yet. For this example, I accepted the default choices.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-3cYzUwllVkM/VNaEkx0srRI/AAAAAAAACDY/vHGFtGF_JOE/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B3.31.05%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-3cYzUwllVkM/VNaEkx0srRI/AAAAAAAACDY/vHGFtGF_JOE/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B3.31.05%2BPM.png" /></a></div>
<br />
In the project target <i>General</i> settings, I can see that Xcode automatically added the framework to the <i>Linked Frameworks and Libraries</i> section. Thank you, Xcode.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-IISYRR3pX3E/VNaYVO4IVnI/AAAAAAAACD4/DlrXbi0oO-8/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B4.55.15%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-IISYRR3pX3E/VNaYVO4IVnI/AAAAAAAACD4/DlrXbi0oO-8/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B4.55.15%2BPM.png" /></a></div>
<br />
And it will build successfully, but when I ran it in the simulator, I hit this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-kyIm5icijPA/VNabSfPQbcI/AAAAAAAACEU/4cd20Bqx9XI/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B5.09.38%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-kyIm5icijPA/VNabSfPQbcI/AAAAAAAACEU/4cd20Bqx9XI/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B5.09.38%2BPM.png" /></a></div>
<br />
With this error message:<br />
<br />
<code>
dyld: Library not loaded: @rpath/BobLib.framework/BobLib
Referenced from: /Users/jeff/Library/Developer/CoreSimulator/Devices/EF59ACE7-ACD5-40CB-92ED-A4BBBBE619F0/data/Containers/Bundle/Application/7151B3F9-A962-44C0-A5A8-84B4AB619697/Pen1.app/Pen1
Reason: image not found
</code>
<br />
<br />
What Xcode did not do is add <b>BobLib</b> to the <i>Embedded Binaries</i> section of the project target <i>General</i> settings. I am not certain if that makes sense or not since I am so new to embedded frameworks.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-yzVkVyGbSqc/VNaZZ6xHUnI/AAAAAAAACEA/NcC6oDoJ08w/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B5.01.14%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-yzVkVyGbSqc/VNaZZ6xHUnI/AAAAAAAACEA/NcC6oDoJ08w/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B5.01.14%2BPM.png" /></a></div>
<br />
Hit the <b>+</b> button, add <i>BobLib.framework</i>, and build and run again.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-Lvuf6bEQaeY/VNaZy8K_KQI/AAAAAAAACEI/UF9dza3bAkM/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B5.03.14%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-Lvuf6bEQaeY/VNaZy8K_KQI/AAAAAAAACEI/UF9dza3bAkM/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B5.03.14%2BPM.png" /></a></div>
For some reason, after adding it to <i>Embedded Binaries</i>, Xcode adds it again to <i>Linked Frameworks and Libraries</i>. I delete that extra one.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-GAcKlGj1_RQ/VNac3y8VKWI/AAAAAAAACEg/YNQFISzJ1Gc/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B5.14.39%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-GAcKlGj1_RQ/VNac3y8VKWI/AAAAAAAACEg/YNQFISzJ1Gc/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B5.14.39%2BPM.png" /></a></div>
<br />
Here is my code in <b>Pen1</b> that will test if the app can use <b>BobLib</b>. Since I only copied the framework build for simulator, I can only test this out on Simulator.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/--LyNpiHcLWg/VNaMI47aXoI/AAAAAAAACDo/tdHunRwbxjs/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B3.54.38%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/--LyNpiHcLWg/VNaMI47aXoI/AAAAAAAACDo/tdHunRwbxjs/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B3.54.38%2BPM.png" /></a></div>
<br />
After doing the above steps. I know the app has successfully used the framework by checking the console.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-W6HqyW5-3zA/VNadV6G8pOI/AAAAAAAACEo/q0RlYo_Agdw/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B5.15.29%2BPM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-W6HqyW5-3zA/VNadV6G8pOI/AAAAAAAACEo/q0RlYo_Agdw/s1600/Screen%2BShot%2B2015-02-07%2Bat%2B5.15.29%2BPM.png" /></a></div>
<br />
One final note. The WWDC 2014 video <i>Building Modern Frameworks</i> is bloody frustrating. The speaker is too enamored of himself, but this would be tolerable if he provided useful information. It is mostly slideshow in which he repeats the stuff we all know from the method naming guidelines. He drones on for 45 minutes before we get to see him play around in Xcode for 10 minutes, and then he casually races past crucial details that are not documented anywhere else on Earth but in this damned video.<br />
<br /></div>
Unknownnoreply@blogger.com5tag:blogger.com,1999:blog-6938084522763168330.post-18323731374360151132014-11-23T19:11:00.000-06:002015-02-07T13:29:03.356-06:00Xcode 6.1.1 GM Seed and _kLSApplicationLockedInStoppedStateKey.This just cost me an hour or so, and I see little mention of it on the Internet.<br />
<br />
Because of bugs involving Swift in Xcode 6.1 (Build: 6A1052d) I was desperate to move to Xcode 6.1.1 pre-release version.<br />
<br />
I uninstalled Xcode 6.1. I scanned for other Xcode-related files left behind and deleted ones that had a high likelihood of not being essential. For example, I left <tt>/usr/bin/xcodebuild</tt> alone because it is part of the <strong>com.apple.pkg.Essentials</strong> package whereas I deleted the files in <tt>/Users/me/Library/Developer/Xcode</tt>.<br />
<br />
I downloaded and installed Xcode 6.1.1. After installation, I tried to start it. A small window appeared that floated on top of everything. It told me that Xcode was being verified. The progress bar took a long time to finish and several moments after it had finished, a dialog popped up to replace the tiny verify progress window. The dialog was the usual warning that you have downloaded this app from the Internet, are you sure you want to open it? I clicked the button that indicated yes, I want to open the app.<br />
<br />
Nothing useful happens. After restarting, trying it all again, getting the same result, I found this log entry on the Console:<br />
<br />
<pre>11/23/14 6:32:47.962 PM launchservicesd[54]: Someone attempted to start application App:"Xcode" asn:0x0-2c02c pid:367 refs=5 @ 0x7f81cae47bc0 but it still has _kLSApplicationLockedInStoppedStateKey=true, so it is is staying stopped. : LASApplication.cp #2517 SetApplicationInStoppedState() q=LSSession 100005/0x186a5 queue
</pre>
<br />
I fiddled around trying different things, and with every attempt I had to wait a long time for the Xcode verification process to finish before finding out if my attempt was successful or not. I even went into <i>System Preferences</i> > <i>Security & Privacy</i> and set "Allow apps downloaded from:" to the value "Anywhere". That did not help. I really hope I remember to set it back.<br />
<br />
If you search the Apple Developer Forums for "_kLSApplicationLockedInStoppedStateKey" you'll get one hit from August this year. Reading the post and response, it seems like it was just a one time thing for that user. He kept trying to open Xcode, and eventually it worked!<br />
<br />
I gave it a shot. I clicked the Xcode icon in the Dock maybe 20 or 30 times in rapid succession. And it seemed to have worked! Xcode opened! I can open my project in Xcode again. I'm scared to press Build. I'm scared to close the Xcode app. Right now, I'm <b>very</b> scared to run the Simulator.<br />
<br />
Right now, I am traumatized. I rarely have this kind of opaque problem with Apple products, even their development tools. This is the first time I've use pre-release development tools, however. It was a horrible reminder of being back on other OSs where I spent too much of my time wrestling with it instead of being productive. I really hate that.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6938084522763168330.post-22183089419994940982014-11-20T10:51:00.004-06:002014-11-20T10:57:02.503-06:00My Swift equivalent of C macro DLog() with __PRETTY_FUNCTION__.I did not see this exact thing out in the wild yet. It is cobbled together from <a href="http://stackoverflow.com/a/26602913/307944">unpopular Stack Overflow answers</a> and <a href="http://sketchytech.blogspot.com/2014/07/swift-join-and-split-explained.html">highly informative blog posts</a>.<br />
<br />
<pre>func dLog(message: String, fullPath: String = __FILE__, line: Int = __LINE__, functionName: String = __FUNCTION__) {
let filename = fullPath.lastPathComponent
// Remove ".swift" from file name.
let splitFilename = split(filename, {(c:Character)->Bool in return c=="."}, allowEmptySlices: false)
let classGuess = splitFilename[0]
// Remove "()" from function name.
let splitFuncName = split(functionName, {(c:Character)->Bool in return c=="("}, allowEmptySlices: false)
let funcName = splitFuncName[0]
NSLog("%@", "[\(classGuess) \(funcName)] [Line \(line)] \(message)")
}
</pre>
<br />
The output looks like this.<br />
<br />
<pre>2014-11-19 18:55:05.887 SandboxApp[12433:287724] [SomeViewController viewDidLoad] [Line 27] dLog message test.
</pre>
<br />
Note that the biggest flaw is the use of the file name instead of the class name. According to Swift docs there is no <tt>__CLASS__</tt> <strong>special literal expression.</strong><br />
<br />
To make this global, I dropped it in the AppDelegate file outside of the AppDelegate class. There has got to be a better convention for global functions, but I am only burning one bridge at a time.<br />
<br />
For bonus points, the Xcode autocomplete on the split() function crashed SourceKitService. I guess this means I'm cutting edge now.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-IHg1oT0briY/VG4bqK2mGVI/AAAAAAAACA0/YuiLfLUS4i4/s1600/Screen%2BShot%2B2014-11-19%2Bat%2B5.49.41%2BPM%2Bcopy.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-IHg1oT0briY/VG4bqK2mGVI/AAAAAAAACA0/YuiLfLUS4i4/s1600/Screen%2BShot%2B2014-11-19%2Bat%2B5.49.41%2BPM%2Bcopy.png" /></a></div>
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6938084522763168330.post-52263535209444891572014-10-11T22:39:00.002-05:002014-10-11T22:41:47.841-05:00GIMP script (Scheme) to scale multiple files at once (batch).I made this back in January of this year, but I forgot to post it. I searched around briefly, but at the time, I found nothing that I could just drop in and use. So I had to write this.<br />
<br />
It is written in Scheme. On my MacBook, I drop this script in <tt>~/Library/Application Support/GIMP/2.8/scripts</tt>. Then from the GIMP menu bar select <strong>Filters | Script-Fu | Refresh Scripts</strong>. This script should then show up under the GIMP menu bar selection <strong>Image | Transform | Batch Scale By Factor</strong>.<br />
<br />
There are a lot of reasons we would need to perform this a batch scale of images files, but mine was related to iOS development. Retina images must be twice the resolution of non-Retina images in order to look good. So I used Retina images as originals and then I had to scale everything to half that size for non-Retina.<br />
<br />
The script does not overwrite the original files. It makes new files with "_.jpg" appended to the file name, even if the file name already ends in ".jpg". Which reminds me, this script saves all files as JPEGs, even if the originals are not. If you want different output, I'm sure you can figure out how to change it.<br />
<br />
Hey, even though I wrote this to not overwrite the originals, I highly recommend that you never operate on originals. Make a copy of your originals in a temp directory and run the batch process on the copies.<br />
<br />
<pre>(define (script-fu-scale-by-factor fileglob factor)
(let*
(
(files (cadr (file-glob fileglob 0)))
)
(do-scale-to files factor)
)
)
(define (do-scale-to files factor)
(while (not (null? files))
(let*
(
(file (car files))
(image (car (gimp-file-load 1 file file)))
(width (car(gimp-image-width image)))
(height (car(gimp-image-height image)))
(newfile (string-append file "_.jpg"))
(drawable (car (gimp-image-get-active-layer image)))
)
(gimp-image-scale image (* width factor) (* height factor))
(gimp-file-save 1 image drawable newfile newfile)
)
(set! files (cdr files))
)
)
(script-fu-register
"script-fu-scale-by-factor" ;func name
"Batch Scale By Factor" ;menu label
"Scale multiple images by given factor." ;description
"Jeffery Martin" ;author
"Copyright 2014\
Fluffy White Puppy Software" ;copyright notice
"2014-01-06" ;date created
"" ;image type that the script works on
SF-STRING "fileglob" "/tmp/photos/image-*.jpg"
SF-VALUE "factor" "0.5"
)
(script-fu-menu-register "script-fu-scale-by-factor" "<Image>/Image/Transform")
</pre>
<br />
Here is what it looks like in operation. Original images files:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-8S6EEKAuDY0/VDn1j4G2YpI/AAAAAAAABzc/v_Jz_uU2ovQ/s1600/gimp%2Bscript%2B1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-8S6EEKAuDY0/VDn1j4G2YpI/AAAAAAAABzc/v_Jz_uU2ovQ/s1600/gimp%2Bscript%2B1.png" /></a></div>
<br />
<br />
Here is the dialog when you run the script.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-xNKnfu0w5fs/VDn2YNJtRRI/AAAAAAAABzk/T7lcxJmUhAU/s1600/gimp%2Bscript%2B3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-xNKnfu0w5fs/VDn2YNJtRRI/AAAAAAAABzk/T7lcxJmUhAU/s1600/gimp%2Bscript%2B3.png" /></a></div>
<br />
<br />
And the directory after the script run.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-SEVz9G7tzEw/VDn2fJ7kpUI/AAAAAAAABzs/aHk5TgN1Odk/s1600/gimp%2Bscript%2B5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-SEVz9G7tzEw/VDn2fJ7kpUI/AAAAAAAABzs/aHk5TgN1Odk/s1600/gimp%2Bscript%2B5.png" /></a></div>
<br />
<br />
And notice that the image files are half the size because I input a scaling factor of 0.5 in the script dialog.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-yPo0j--zI0Y/VDn3dPaEnOI/AAAAAAAABz0/xcEW2M4o-nY/s1600/gimp%2Bscript%2B7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-yPo0j--zI0Y/VDn3dPaEnOI/AAAAAAAABz0/xcEW2M4o-nY/s1600/gimp%2Bscript%2B7.png" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-ZuNASlTjExE/VDn3fjCi9vI/AAAAAAAABz8/azItF7y1wEg/s1600/gimp%2Bscript%2B6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-ZuNASlTjExE/VDn3fjCi9vI/AAAAAAAABz8/azItF7y1wEg/s1600/gimp%2Bscript%2B6.png" /></a></div>
Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-6938084522763168330.post-10694280834918976062014-09-09T12:35:00.001-05:002014-10-17T14:56:57.326-05:00SOILD: new object oriented design principles.Is your object oriented design <i>soiled</i>?<br />
<br />
<span style="font-size: large;"><b>
SOILD</b></span><br />
<br />
<b>S</b> = <i>Slippery</i>. The class should be so abstract that’s its responsibility – or even better responsibilities (plural) – should be hard to pin down.<br />
<b>O</b> = <i>Open</i>. The class should be open…to everything! Public. Free as in beer. You get the idea.<br />
<b>I</b> = <i>Interface</i>. Integrate your interface. Turn those façades upside-down.<br />
<b>L</b> = <i>LISP</i>. All braces in your code should be replaceable by parenthesis.<br />
<b>D</b> = Dependency. See poem below.<br />
<br />
No class is an Island, entire of itself; every class is a piece of the Code, a part of the main(); if a clod be washed away by the sea, The Bay Area is the less, as well as if Oakland were, as well as if an old warehouse of thy startup or the Apple Spaceship Campus were; any freed object diminishes the app, because the app is involved in the Framework; And therefore never send to know for whom the compiler warns; It warns for thee.<br />
<div>
<br />
<span style="font-size: xx-small;">Hopefully, what I am about to write is obvious, but if not, please realize that this post is humor. I was making a joke about the SOLID OO programming design principles.</span></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6938084522763168330.post-82449444931322279452014-09-08T21:54:00.001-05:002014-09-08T22:13:08.900-05:00OS X display preferences and melatonin suppression from cool/blue/white light.If you search around you will find enough <a href="http://www.sciencedaily.com/releases/2011/09/110912092554.htm">scientific articles</a> explaining how light with cool color temperatures (lots of blue wavelength) suppresses the human brain's production of melatonin. Melatonin, of course, is a hormone needed for a good night of sleep. This fact impacts those of us who may be in front of LCD screens just before or well after midnight.<br />
<br />
One way to help with this is to switch your monitor's settings to a warm color temperature. I noticed that some folks are selling apps for OS X so that you can make this adjustment. Well, there is no reason to download or buy an app.<br />
<br />
Go to <b>System Preferences</b> <b>:</b> <b>Displays</b> and select the <b>Color</b> tab. Then tap the <i>Calibrate</i> button to create a new profile. When it comes time to "Select a target white point" choose <i><b>D50</b> Warm yellowish white</i>. Save the profile with a memorable name, and then when you are coding after sunset, switch to the warm color temperature profile.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-RquseSIWUYo/VA5rNFbRIkI/AAAAAAAABT4/Ddk6_wmwUkc/s1600/color%2Bprofile%2Bss%2B1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-RquseSIWUYo/VA5rNFbRIkI/AAAAAAAABT4/Ddk6_wmwUkc/s1600/color%2Bprofile%2Bss%2B1.png" /></a></div>
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6938084522763168330.post-68279319785396660792014-08-08T23:37:00.001-05:002014-08-08T23:37:15.750-05:00Cocoa documentation has an image that tickles me.<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-5sFX2mczKgk/U-Wev-uKt5I/AAAAAAAABTo/-NWTieHBFew/s1600/object_creation.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-5sFX2mczKgk/U-Wev-uKt5I/AAAAAAAABTo/-NWTieHBFew/s1600/object_creation.jpg" /></a></div>
<br />
It is from the <i>Cocoa Core Competencies</i> document, in the <a href="https://developer.apple.com/library/ios/documentation/General/Conceptual/DevPedia-CocoaCore/ObjectCreation.html">section "Object Creation"</a>. I like explaining things by analogy, perhaps too much because my analogies do not always work. I think this one gets the point across. It is understandable across all modern computer-using Earth cultures. I like it. It is effective and well done.<br />
<br />
However, I would display the resource picture as bills of currency and the allocation as the individual ingredients, and I would remove the dough mixer. The resource is the computer's memory, not your code pieces and data parts (ingredients). Allocation is when you claim some memory and fill it with your code and data (convert your currency into flour, salt, yeast, and water). The way the analogy is now, it doesn't emphasize enough the conversion of a homogenous limited resource (memory/money) into a useful item. In fact, it shows that your methods and instance variables (flour and yeast) are the resource, and they aren't.<br />
<br />
I don't think my imagined changes would help a beginner understand OOD/OOP better. I just think it would make the analogy more accurate. Are computer engineering basics taught to computer programmers these days? If yes then perhaps a more accurate analogy <b>would</b> help after all.<br />
<br />
Has anyone written a class that has an <tt>initWithTemperature:</tt> method?Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6938084522763168330.post-3636335214870725562014-07-10T17:36:00.000-05:002014-07-10T17:36:26.834-05:00Stop using icons.I am writing this in the month of July in the year two thousand fourteen of Anno Domini / Common Era.<br />
<br />
I was using Google Chrome 35.0.1916.153 and Mac OS X 10.9.4.<br />
<br />
I clicked a link in Chrome pointing to a PDF file. The file displayed in a Chrome tab. I just wanted to save it locally. This floating toolbar was in the bottom right corner of the screen.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-CUeS2UJh-zg/U78PDLpGHRI/AAAAAAAABS8/dtHUdUtFe3c/s1600/menu+icons.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-CUeS2UJh-zg/U78PDLpGHRI/AAAAAAAABS8/dtHUdUtFe3c/s1600/menu+icons.png" /></a></div>
<br />
I recall the era of the 3½ inch floppy disk. As a teenager, I used 5¼ inch floppy disks to load programs into my Atari 800. In the 90s, we used Zip drives and later Jazz drives.<br />
<br />
<b>But come on!</b> I had to hesitate far too long hovering over that button (with no tooltip) wondering if it meant what I hoped it meant. I was also anxious it would do something destructive and annoying to reverse.<br />
<br />
I think my pause was due to two factors: I had not seen a floppy disk in so long that I was not sure if the silhouette matched one, and I was in disbelief that a modern UI designer would use this image to represent "save".<br />
<br />
The only icons I recognize on that toolbar are <i>zoom out</i> and <i>zoom in</i>. I've got a crazy solution. Look at my Gmail message-level toolbar.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-DNJxQ8OmXXg/U78TvndFyEI/AAAAAAAABTI/huk1skTgcyQ/s1600/Screen+Shot+2014-07-10+at+5.04.45+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-DNJxQ8OmXXg/U78TvndFyEI/AAAAAAAABTI/huk1skTgcyQ/s1600/Screen+Shot+2014-07-10+at+5.04.45+PM.png" /></a></div>
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6938084522763168330.post-21067580844641126002014-05-07T19:48:00.002-05:002014-05-18T15:03:14.910-05:00My image editor for Mac OS X is now Acorn.I moved from Linux to OS X years ago, but I still kept going to GIMP for image editing. Keep in mind that only in the last year or so has GIMP become Cocoa-native. Prior to that it required an X11 runtime that was available as an installable extra from Apple.<br />
<br />
Running GIMP inside X11 on OS X looked poor with the antiquated GTK+ widget set. The runtime situation made it impossible to <b>directly</b> <i>Alt+Tab</i> to GIMP; the X11 process would gain focus instead. The GIMP shortcut keys used <i>Control</i> instead of <i>Command</i>. There we other quirks I cannot remember now.<br />
<br />
When GIMP become Cocoa-native, I was relieved. But a keyboard focus bug caused text entered into text fields to be interpreted as <i>Alt+Key</i> strokes, which are shortcut keys for menu items. Fine, so I disabled all shortcut keys in the app and did <b>everything</b> solely from touchpad clicks. In the next version, that bug got fixed but not the bug that fails to order files by name properly.<br />
<br />
Yesterday, in GIMP, I was trying to figure out why I could not select a layer in the <i>Layer</i> dialog. I had already converted my floating selection to a new layer, so what could be the problem? GIMP hung as I poked around, and I had to force quit it. At that point, I decided to buy an image editor.<br />
<br />
I had previously researched other image editors for Mac OS X, but the different choices were daunting. The review articles I had found were either outdated or incomplete (missing a prominent application). Finally, in a bogus article which I will not link to, several comments to that article recommended <a href="http://flyingmeat.com/acorn/">Acorn</a>. I took a look at the feature list of Acorn, and I was impressed. It only cost $30, and I trust the crowd more than a self-appointed authority on those user-generated content repositories, so I bought it.<br />
<br />
What a huge difference! I am still in the process of kicking myself for being so foolish as to not leave GIMP earlier. I rate GIMP's ease-of-use at 3 (out of 10). I rate Acorn's at 9 (because nothing is perfect). Exploring Acorn to figure out how to do something is fast, simple, and straightforward. I had to look up how to add to a selection, and the Acorn documentation is up-to-date and complete with good search results.<br />
<br />
And that brings me to what really struck me about the difference. In GIMP I had seen the different selection method (add, subtract, union) mini-buttons before, but until Acorn it was all just so much clutter in my face that I never thought about what to do with those buttons. So suddenly, because of Acorn's superior UI design and full documentation, my skills as an editor of images have increased.<br />
<br />
For those of you thinking I should use Photoshop, Photoshop Lightroom, or Photoshop Elements: just no, guys. I think I tried out Lightroom, and what a convoluted mess. The install was odd somehow. The look and feel was that wannabe nouveau Adobe Flex. It tried to take over my Mac by asking me about all my images and whatnot. And the UI was like advanced GIMP. I went running back to GIMP very quickly. The next time I tried to give Lightroom another chance my trail period had expired, and I decided it was not worth it to pursue again.<br />
<br />
To those who might think this product review was unfair: I did not set out to write a product review when I started using PS Lightroom, Acorn, or GIMP. I'm just a guy who used GIMP on OS X for far too long, and I used the immense power of an inference engine that I keep stored in my skull, and the output I got from the input provided lead me to spend $30 on Acorn, and I'm very happy with that decision. In fact, I'm so pleased that I wrote this blog entry about it.<br />
<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6938084522763168330.post-75490173562944259952014-02-17T13:45:00.003-06:002014-05-07T17:55:18.191-05:00 My iPad app is available: Veronica's Garden Tracker.<br />
Please tell every gardener you know about <a href="https://itunes.apple.com/us/app/veronicas-garden-tracker/id794641225">Veronica's Garden Tracker</a> for iPad. Thanks!<br />
<div>
<br /></div>
<div>
<div>
I aimed to create a simple, visual journal for home vegetable gardens. I got the idea when I asked my wife a few years back, "Sweetie, what is this sprouting here?" and she had forgotten and her labels were missing, so we had to wait a few weeks until the plants got bigger to find the answer.</div>
</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6938084522763168330.post-80263984446697772272014-02-17T13:40:00.001-06:002014-05-07T19:55:22.970-05:00Google AdWords redeem coupon code screen has moved.It took me a bit to find the new location to redeem those promotional codes that Google hands out to lure in folks like me into using AdWords. All the blogs out there talk about the old, easier-to-find location. Even the email that contains the promo code itself is wrong.<br />
<ol>
<li>Starting from AdWords home.</li>
<li>Click gear icon in upper right.</li>
<li>Click <i>Billing</i> from drop down menu.</li>
<li>Click Transaction history.</li>
<li>Click <i>More Actions</i> button.</li>
<li>Click <i>Apply a promotional code</i> from the drop down menu.</li>
<li>And there you are!</li>
</ol>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6938084522763168330.post-9753519823642979642013-12-11T19:37:00.000-06:002013-12-11T20:40:09.330-06:00Order that UIScrollViewDelegate methods get called when a user does a sloppy tap.Please note that the UIScrollView I am using has <tt>pagingEnabled</tt> set to <tt>YES</tt>.<br />
<br />
To create the sloppy tap gesture, the user makes the most minor drag motion possible with his finger. I call this a "sloppy tap" because about 1 in 10 of my own taps trigger this gesture on my iPad 2. Visually, the scroll view will not appear to move.<br />
<br />
<ol>
<li><tt>scrollViewWillBeginDragging:</tt></li>
<li><tt>scrollViewDidEndDragging:willDecelerate:</tt></li>
</ol>
Note that <tt>scrollViewDidEndDecelerating:</tt> will not be called because no scrolling actually happened.<br />
<br />
Here is what gets called when a user properly flicks his finger horizontally to scroll to a new page.<br />
<br />
<ol>
<li><tt>scrollViewWillBeginDragging:</tt></li>
<li><tt>scrollViewDidScroll:</tt> × ~4</li>
<li><tt>scrollViewDidEndDragging:willDecelerate:</tt></li>
<li><tt>scrollViewDidScroll:</tt> × ~24;</li>
<li><tt>scrollViewDidEndDecelerating:</tt></li>
</ol>
Suppose you want a flag toggled as soon as movement starts, and then you want it toggled again only after movement stops. There isn't one method you can count on for the second flip.<br />
<br />
I already toggle the flag in <tt>scrollViewWillBeginDragging:</tt> and <tt>scrollViewDidEndDecelerating:</tt>. The solution is to also toggle the flag in <tt>scrollViewDidEndDragging:willDecelerate:</tt> when <tt>decelerate</tt> is <tt>NO</tt>.<br />
<br />
I would have figured this out sooner if I had read the <a href="https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/UIScrollView_pg/ScrollingViewContent/ScrollingViewContent.html">documentation</a> more closely.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6938084522763168330.post-67427246162394059922013-12-06T11:13:00.001-06:002013-12-06T11:13:54.487-06:00lldb and Objective C: printing structs contained in objects.I'm tired of looking up how to do this.<br />
<br />
<span style="color: red;">Wrong:</span><br />
<pre>(lldb) expr -- self.scrollView.frame
error: unsupported expression with unknown type
error: unsupported expression with unknown type
error: 2 errors parsing expression
(lldb) expr -- (CGRect)self.scrollView.frame
error: unsupported expression with unknown type
error: unsupported expression with unknown type
error: C-style cast from 'unknown type' to 'CGRect' is not allowed
error: 3 errors parsing expression
</pre>
<br />
<span style="color: lime;">Correct:</span><br />
<pre>(lldb) expr -- (CGRect)[[self scrollView]frame]
(CGRect) $5 = origin=(x=0, y=0) size=(width=768, height=607)
</pre>
<br />
You'll notice I don't bother with <b>gdb</b> aliases like <i>p</i>. Please accept my apologies.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6938084522763168330.post-65285495426492825772013-12-05T11:21:00.001-06:002013-12-05T11:21:56.126-06:00[CALayer isKindOfClass:]: message sent to deallocated instance -- Get this error when using UINavigationController.This is a tough one to debug, and I did not find many examples out there on solving this.<br />
<br />
I was getting this error when manipulating my Navigation Controller stack via <tt>pushViewController</tt>. Here are the recreation steps:<br />
<br />
<ol>
<li>Due to user action, ViewControllerSubclassA instance X gets pushed to Navigation Controller stack.</li>
<li>Due to user action, instance X pops itself from stack.</li>
<li>Due to user action, ViewControllerSubclassA instance Y gets pushed to Navigation Controller stack.</li>
<li>Crash happens!</li>
</ol>
<br />
There are going to be a thousand different reasons out there for this to occur, but I wanted to document my particular one in order to help.<br />
<br />
I narrowed things down to which view by testing the app. I noticed that the crash only happened after I had tapped in a text field owned by ViewControllerSubclassA. Was a reference to a UITextField owned by a view controller still hanging around after the view controller was popped from the navigation controller stack? I added a debug line to find out.<br />
<br />
<pre>2013-12-05 10:20:19.504 MyApp[82746:70b] -[MATypeAViewController viewDidLoad] [Line 50] CALayer of textField = CALayer: 0xefe5dd0
2013-12-05 10:20:27.373 MyApp[82746:70b] *** -[CALayer isKindOfClass:]: message sent to deallocated instance 0xefe5dd0
</pre>
<br />
Yep, it sure was.<br />
<br />
Removing this UITextFieldDelegate protocol method from my view controller solved the problem.<br />
<br />
<pre>- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
if ([textField.text length] == MATextFieldIllegalLength)
{
return NO;
}
return YES;
}
</pre>
<br />
What I <i>guess</i> was happening was that at times, NO was returned from this method, but the view controller popped itself from the stack anyway. This left a reference <i>somewhere</i> to the UITextField even though it got deallocated when its view controller went away.Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-6938084522763168330.post-15260188180824348322013-12-02T16:36:00.001-06:002013-12-02T16:36:20.000-06:00Jeff's first rule of programming.Number of known software defects with an as-yet-unknown root cause of the type <i>Boolean semantic error</i> figured out per 1 km jogged while casually considering said defect: 1.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6938084522763168330.post-43393607742257628262013-11-21T14:04:00.000-06:002013-11-21T14:04:30.057-06:00UIColor HSB/HSV 360 degree to 0.0 thru 1.0 decimal conversion and bc.As we all know, UIColor's method <tt>colorWithHue:saturation:brightness:alpha:</tt> maps the hue argument to a value between 0.0 and 1.0. Out in the real world, this is a value from 0 to 360. So after I'm done color shopping, I use <strong>bc</strong> to convert the hue values to the proper range from the UIKit framework. Unfortunately, I left <strong>bc</strong> with my usual <em>scale</em> value of 3.<br />
<br />
Yes, a 5th grader would quickly realize how bad my mistake was, but I'm no 5th grader. It took me a while.<br />
<br />
An example:<br />
<br />
<pre>scale=3
(1/360) * 140
.280
scale=5
(1/360) * 140
.3878</pre>
<br />
Yikes! No wonder everything looked funny.Unknownnoreply@blogger.com0