0
\$\begingroup\$

I am building an iOS SDK to be consumed by apps. I am building an object that represents a physical place. The interface looks like so:

@interface RDPlace : NSObject

@property (nonatomic, strong, readonly) NSString *city;

@property (nonatomic, strong, readonly) NSString *country;

@property (nonatomic, strong, readonly) NSString *address;

@property (nonatomic, strong, readonly) NSString *zip;

@end

This is all working fine, but now I am attempting to make this work outside of the US. I found out that some places (Hong Kong was the one that prompted this discovery) don't have a zip code. I'm wondering what the best value to put in this SDK is. I believe I have 3 options:

  1. RDPlaces with no zip have the property set to nil
  2. RDPlaces with no zip have the property set to NSNull
  3. RDPlaces with no zip have the property set to @"" (empty string)

What is the most friendly for consumers of this object, and how would one annotate this for swift?

\$\endgroup\$
  • 2
    \$\begingroup\$ Useful related reading: Falsehoods programmers believe about addresses \$\endgroup\$ – 200_success Mar 25 '16 at 20:01
  • \$\begingroup\$ For good measure, could you tell us more about what the purpose of your SDK is? \$\endgroup\$ – 200_success Mar 25 '16 at 20:02
  • \$\begingroup\$ This SDK is meant to return data on places when the user enters them, however, if my API is unable to get that specific data (either because it isnt there like the HK zips, or I just cant find it). Another example is I want to add the "website" property for if the place is a business, but if a place doesn't have a website, or I just can't find it, I want to know if implementers of my SDK would be expecting NSNull, nil, or an empty version of that object (@"", @[], etc.) \$\endgroup\$ – arc4randall Mar 25 '16 at 20:07
  • \$\begingroup\$ The properties here are always filled by your code? That is, RDPlaces are solely vended by the SDK, not created from scratch by clients? \$\endgroup\$ – jscs Mar 25 '16 at 20:25
  • \$\begingroup\$ Yes. All the properties are readonly. When you enter a place, the delegate calls a method which gives you a RDPlace for the location you just entered, but nobody can change the properties on an RDPlace object, because it represents a place in the real world. Just like how you can't change the name of the local CVS to be Target or something \$\endgroup\$ – arc4randall Mar 25 '16 at 20:28
3
\$\begingroup\$

You're trying to solve a solved problem.

Just use CLPlacemark out of Core Location. It has already solved all the problems you've brought up in your question: how to handle international addresses, what all the necessary fields are, how to handle missing fields, and how to interop with Swift.

Worse case scenario, if CLPlacemark isn't quite what you need, you can either subclass it or model your place object closely around this object.

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

I think the concerns here about accurately modelling international addresses are well founded but the root question seems to be a simpler problem.

Given an object with some properties which may not be set I would expect them to contain nil values. If correctly annotated with _Nullable then these will become Swift optionals which should be both very familiar to your SDK's consumers and provide good compiler support for type checking use of those properties.

Use of NSNull will obscure type information in the interface (the property can now be a NSNull or NSString so it will have to be an AnyObject or id at which point I have to read the documentation to confirm it it might also sometimes be NSNumber or something else as well). In Swift I have to introduce failable cast operations to safely use the value. In objective-c I have to be even more careful since I get less compiler feedback about unsafe casts and while I might expect [zip length] to return nil I now need to make sure not to attempt to send length to a NSNull.

Use of magic values like ""similarly requires that consumers of this SDK rely on documentation rather than their type system. Checks against some magic value are less likely to be consistently enforced and more likely to be brittle when they are in place.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Yes, this is what I was looking for. So as a consumer of an SDK, you wouldn't find it weird if 5 of 15 properties were nil for example? Should I find a way to make multiple subclasses of RDPlace to minimize the number of nils any given object would have? Or do you think its fine having many nils on one object? \$\endgroup\$ – arc4randall Mar 26 '16 at 19:43
  • \$\begingroup\$ I wouldn't worry about the absolute number of optional properties but I would look for opportunities to limit the number of permutations. If some of these properties are always nil or non-nil together consider grouping them into a child struct or class of RDPlace. For example prefer giving the Place an optional Geolocation containing a non-optional latitude and longitude to having both latitude and longitude as optionals directly on Place. That way I know I never have to consider how I'm supposed to displace a Place with only one of those values. \$\endgroup\$ – Jonah Mar 26 '16 at 21:17
1
\$\begingroup\$

I'll admit that I'm not entirely clear on what you're trying to accomplish here. What you've posted is pretty minimal, but I think it's a good illustration of what can go wrong in situations like this. Here are a few thoughts:

It turns out that there are several problems with what seem like simple concepts in everyday life. @200_success already pointed out common problems with addresses. But it's way worse than that.

It turns out that the concept of even the largest structure you've listed (country) is really tricky to deal with. For example, the area of Earth that some call "Taiwan" is also called "Chinese Taipei" by others, and it's important to get it right when displaying it to certain users.

But it's way worse than that. There are some areas that aren't recognized as countries at all! And it's not some anomaly. There are several areas that currently meet this criteria.

My suggestion would be to rethink how your users will retrieve the data they need. You're probably better off with something objective like longitude and latitude. At the very least, you may need to offer alternate values for these fields.

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

What is the difference between a zip set to nil and one set to @""?

IMHO, for all practical purposes, there is none. But allowing the zip to be nil will, in some situations especially in Swift, force the user to both check for nil and check to see if the zip is empty before being able to determine that there is no zip associated with that particular object.

Why force your users to go through all that work? The zip field should always contain a string. An empty string means no zip.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.