Swift Regex Deep Dive
iOS MacOur introductory guide to Swift Regex. Learn regular expressions in Swift including RegexBuilder examples and strongly-typed captures.
Readers of this blog might notice a pattern in my postings. They’re occasionally accompanied by a small program to demonstrate some interesting point.
Much of the sample code in Advanced Mac OS X Programming : The Big Nerd Ranch Guide are in a similar form: a small stand-alone program that demonstrates some isolated bit of functionality.
I love small little programs. They’re not just a pedagogical tool (even though they’re great for that). I find them invaluable when I need an answer to a question about how something works, or if I’m tracking down some kind of misbehavior whether from a bug or just my own misunderstanding.
I have a directory, ~/junk
, where I put these little one offs. You can tell I’ve collected a couple (and I clean out the junk pile every now and then!)
Ever been involved in a discussion, either in person, or online line via email or IRC? One of those speculation threads on how something works. Person A thinks it works one way. Person B remembers hearing something from someone about how it works a different way. Person C used it years ago and remembered it working the first way. Around and around it goes. Sometimes some interesting ideas are tossed around, but often it can be a waste of time. I tend to be the party pooper by taking a minute or three and trying it in a test program.
It’s like the Scientific Process. You have a hypothesis. You write an experiment to test that hypothesis. You get some data based on that outcome, and then feed that data back into your personal pile of understanding.
One little piece of performance art I do in my classes and when I give my “Thoughts on Debugging” talk is to demonstrate writing and running one of these little programs in a couple of minutes – complete with typos. Many editors include built-in shell access which makes doing a quick command-line compile very easy. There are also standalone snippet tools that will let you run chunks of Objective-C (or many other languages) without the hassle of making a brand new Xcode project for each one.
Just the other day, we had a style discussion about where nonatomic
should live in a property declaration. At the beginning, where it’s been historically:
@property (nonatomic, assign) NSInteger frobnozzle;
or at the end
@property (assign, nonatomic) NSInteger frobnozzle;
As far as the compiler is concerned, they’re the same. The argument for having nonatomic
at the end was that you could use the macro NS_NONATOMIC_IOSONLY
for shared code:
@property (assign, NS_NONATOMIC_IOSONLY) NSInteger frobnozzle;
That macro evaluates to nonatomic
on iOS, and to nothing on Mac OS X. This macro has to be the last one in the list, because the compiler will happily eat a comma at the end of the list:
@property (assign, ) NSInteger frobnozzle;
But not at the beginning:
@property (, assign) NSInteger frobnozzle;
Giving an error:
atomic.m:8:12: error: expected ')'
@property (, assign) NSInteger commaAtBeginning;
^
atomic.m:8:11: note: to match this '('
@property (, assign) NSInteger commaAtBeginning;
So, by putting nonatomic
at the end it becomes easier to migrate some iOS code to be shared with its desktop counterparts as well. Just replace atomic with NS_NONATOMIC_IOSONLY
, and you’re done with that part.
Easy enough to test that leading/trailing comma hypothesis with a little program (the final version can be found at this gist):
#import <Foundation/Foundation.h>
// clang -g -Wall -framework Foundation -o atomic atomic.m
@interface Blah : NSObject
@property (assign, NS_NONATOMIC_IOSONLY) NSInteger frobnozzle;
@property (assign, ) NSInteger commaAtEnd;
@property (, assign) NSInteger commaAtBeginning; // Syntax error
@end // Blah
@implementation Blah
@end // Blah
int main (void) {
return 0;
} // main
I only had to compile it and see what happens. No need to actually run anything. Sure enough, comma at the beginning of the list is rejected, and a comma at the end of the list is allowed. The question that came up next was “why does NS_NONATOMIC_IOSONLY
evaluate to nothing, and not atomic
”. The thought was atomic
doesn’t exist because it’s the default. A quick tweak to the test program showed that atomic actually does exist:
@property (atomic, assign) NSInteger blah;
This compiled ok. Just to make sure that this atomic
actually means “Objective-C property access atomic”, I added a getter but not a setter. The compiler warns in the case where one part of the property access is compiler-generated, and the other part is implemented in the source file. This makes sense because we can’t correctly assume how the compiler will be making the property atomic. If the setter is using one technique and our code is using another, it’s no longer an atomic property.
(Just a reminder that atomic properties don’t mean it’s thread safe, just that assigning and reading the value of the instance variable will occur in its entirety. If you have explicit thread safety requirements, you’ll need to use something like the atomic test and set calls, locks, queues, and so on.)
So, I added a getter:
- (NSInteger) blah {
return _blah;
} // blah
And sure enough, the compiler warns:
atomic.m:16:1: warning: writable atomic property 'blah' cannot pair a synthesized setter with a user
defined getter [-Watomic-property-with-user-defined-accessor]
- (NSInteger) blah {
^
atomic.m:16:1: note: setter and getter must both be synthesized, or both be user defined,or the property
must be nonatomic
atomic.m:9:38: note: property declared here
@property (atomic, assign) NSInteger blah;
^
This is interesting data. Clang has support for explicit atomic properties. Yet that NS_NONATOMIC_IOSONLY
macro evaluates to nothing. Looking at the compiler source code, ParseObjc.cpp
has code for finding atomic properties:
else if (II->isStr("nonatomic"))
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nonatomic);
else if (II->isStr("atomic"))
DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_atomic);
But Apple’s documentation only mentions nonatomic
, and in fact says that “There is no keyword to denote atomic.”
Now I’m curious. Maybe there’s another reason. Nowadays with clang
being so good, I forget about gcc
. Maybe gcc
has problems with the atomic keyword. Let’s check.
I added a new compiler line to the top:
// gcc -g -Wall -framework Foundation -o atomic atomic.m
Copy and paste it into a shell and build it:
% gcc -g -Wall -framework Foundation -o atomic atomic.m
atomic.m:9: error: expected a property attribute before ‘atomic'
Yep. gcc doesn’t like that. A quick browse of the gcc source shows that nonatomic
is the only keyword in c-parser.c:
...
{ "retain", RID_RETAIN, D_OBJC },
{ "copy", RID_COPY, D_OBJC },
/* APPLE LOCAL end objc new property */
/* APPLE LOCAL radar 4947014 - objc atomic property */
{ "nonatomic", RID_NONATOMIC, D_OBJC },
};
So, indeed in gcc
, there is no atomic
property for Objective-C. Not all the mysteries are solved (is atomic
really OK to use if we’re not going to be using gcc?), but it does explain why NS_NONATOMIC_IOSONLY
is the way it is, because it needs to be compatible with gcc
.
_Interested in debugging, command-line tools, the compiler, and similar low-level nerdity? Come to my Advanced Mac OS X Bootcamp, January in the Netherlands, and February in Atlanta. Or stop by and say “Hi” to the Ranchers at CocoaConf Raleigh in November.
_
Our introductory guide to Swift Regex. Learn regular expressions in Swift including RegexBuilder examples and strongly-typed captures.
The Combine framework in Swift is a powerful declarative API for the asynchronous processing of values over time. It takes full advantage of Swift...
SwiftUI has changed a great many things about how developers create applications for iOS, and not just in the way we lay out our...