Q&A – Cocoanetics https://www.cocoanetics.com Our DNA is written in Swift Sat, 28 Apr 2018 08:00:45 +0000 en-US hourly 1 https://wordpress.org/?v=6.4.3 39982308 QA: Apple slowing down older iPhones https://www.cocoanetics.com/2018/03/qa-do-you-think-apple-deliberately-slowed-down-the-performance-of-the-older-iphones/ https://www.cocoanetics.com/2018/03/qa-do-you-think-apple-deliberately-slowed-down-the-performance-of-the-older-iphones/#comments Wed, 07 Mar 2018 15:45:51 +0000 https://www.cocoanetics.com/?p=10558 Tara from MacFixIt Australia asked:

Do you think Apple deliberately slowed down the performance of the older iPhones?

Sorry, but everybody following the story knows what happened and that the question is wrong. Rather you should have asked it to be technically accurate.

Update, April 28th: MacFixIt Austria used parts of my comment in a larger post.

Apple was having the problem that iPhones with older batteries shut down under load, while the battery gauge showed that it was still 30% or more charged. I was hit by this myself multiple times listening to podcasts (over cellular), on bluetooth headphones while it was relatively cold outside.

So Apple decided to throttle devices meeting certain conditions to avoid this unfortunate shutdown. Apple solved the issue as they always do: they gather a lot of data, „captured“ iPhones that were being sent in by people like me to have an AppleCare exchange for this reason, and then they devised a technical solution that would limit the number of shutdowns.

What they didn’t do is to properly communicate their conclusions and decided upon solution, maybe hoping that most people would move on to newer phones and thus the problem going away by itself. When somebody noticed that their iPhone suddenly performed like new, after having gotten a new battery, the whole story came to light.

Now about my opinion: since we cannot do anything about Lithion-Ion batteries having a limited life span and Apple decided to not have user-replaceable batteries, there need to be several things happening:

  1. Users need to be made aware right from the start that they can only charge their new iPhone a limited number of times. Also this information needs to be easily accessible via the system information facilities.
  2. When batteries have reached the end of their useful life the user should be asked whether they want to continue to use it at degraded performance, get an inexpensive replacement battery or get a discount for trading in their phones (so that the battery can be recycled)

Apple seems to be doing all of this now. My opinion is that it should not have needed such a media uproar for them to being proactive in that regard. By waiting until “somebody complained“ the damage is now done that people tend to think Apple was doing it intentionally, to avoid service costs (from people calling AppleCare and getting devices replaced) and to leave this thorn in peoples side that might cause them to upgrade to new devices sooner.

Long story short: Apple should have acted more openly and sooner and communicated modifications they did to users phones (to their benefit) unmisunderstandably.

 

]]>
https://www.cocoanetics.com/2018/03/qa-do-you-think-apple-deliberately-slowed-down-the-performance-of-the-older-iphones/feed/ 1 10558
The Exclamation Function https://www.cocoanetics.com/2017/01/the-exclamation-function/ https://www.cocoanetics.com/2017/01/the-exclamation-function/#respond Sat, 21 Jan 2017 18:17:49 +0000 https://www.cocoanetics.com/?p=10372 Four months ago, I reported a scenario where LLVM would crash with a segmentation fault. A later Xcode version fixed the LLVM crash, but now the crash would occur during runtime. This surprised me: Why would it be valid syntax accepted by the compiler, yet crash during execution?

The code in question was:

try! JSONSerialization.data(withJSONObject: !, options: [])

Please ignore the “try” which was necessary to shorten the code to the fewest number of lines without having to add a try/catch. You are looking at the lone exclamation mark. In case you wonder how I ended up with this code: I don’t quite remember if it was a faulty migration to Swift 3 by some earlier Xcode version, or me removing some code by accident.

“Swift 3” is one hint that might put you on the right track. At this version, when the great API renaming took place, Apple replaced many instances of AnyObject with Any. That’s also when we learned that numbers and Strings are no longer automatically counted as objects, but als value types akin to structs. This is also the reason why we had to change to many typed Swift dictionaries and arrays to be using Any.

Nick Lockwood was first in providing the correct explanation to the riddle:

AnyObject only accepts objects, but Any accepts everything! Even references to functions. Operator overloading functions only have the operator as their name, and they need no arguments to reference the function itself.

This was later confirmed by Joe from Apple, whose elaborate explanation pleasantly surprised me by e-mail, 9 days later.

Swift considers operators to be regular functions with sugared application syntax. ‘!’ as an expression by itself references the `prefix func !(Bool) -> Bool` in the standard library. That isn’t particularly useful in your code, of course, but you can also do things like ‘array.reduce(0, +)’ to sum the values of an array.

The compiler crashed due to a bug handing function arguments off to ObjC APIs that expect an `id`, though of course NSJSONSerialization doesn’t expect to have a block object in a JSON tree and still fails at runtime.

There you have it. Nick was right all along. 😉

Conclusion

Swift 3 changing AnyObject to Any as the equivalent to id opened the door to a new class of problem that might arise when you are calling the Swift version of something that internally has been implemented in Objective-C.

This change was necessary so that you can still pass strings and number value types Objective-C code which expects an id, like NSArray without lightweight generics to name one example. But this had the somewhat unfortunate side effect that now you can also pass function references as well, whenever the underlying Objective-C code expects an id.

But at least we now know the solution to the initial riddle: ! is a valid reference to a function.

]]>
https://www.cocoanetics.com/2017/01/the-exclamation-function/feed/ 0 10372
Steve’s Senior Moment https://www.cocoanetics.com/2016/03/steves-senior-moment/ https://www.cocoanetics.com/2016/03/steves-senior-moment/#comments Sun, 27 Mar 2016 08:16:24 +0000 https://www.cocoanetics.com/?p=10183 Stefan “Steve” Gugarel came on board of Drobnik KG on April 1st, 2012. He took over main responsibility of the day-to-day development for our most important client at that time. Now, in 2016, he has accrued 8 years of experience in software development, which earns him the status of Senior Developer.

With the average churn in IT being at around 2 years, it is unusual for anyone to stick around that long. So why did he? We asked him.

When it became clear that Steve wanted to work with us – in 2012 – I gave him the choice of either working as a contractor or as employee. He wisely chose the latter, knowing that while making less in the short term it would be the beginning of a way more fulfilling career being part of a team long term.

Steve, congratulations of making it to “Senior Level!”

With the new level you also get an increase in your salary. You now officially make more as employee than I did the last time when I was employed, 7 years ago.

Would you mind providing us with a nice “in action” photo of yours and answer a few questions?

Thanks for the honors, I’d be glad to!

Steve's 4th Anniversary

This photo took only 3 hours, clearly I am better at programming than I am at doing photo shootings… 😉

How did you get into programming?

When I was a child, my parents gave me a learning computer, a PreComputer1000. This allowed you to program in BASIC and so I copied programs from the manual, typing into this box. You would enter code line by line and only when you had typed in all lines you would see if the program was working.

Precomputer

I remember that this was quite frustrating because the power cable would easily come out of the computer. When it did the whole work was lost. But even back then I was quite fascinated that I could easily make programs with input and output.

Did you ever become something different than a programmer when you grew up?

I honestly don’t remember. My parents claim that I wanted to become a priest. 😀

How did you discover Hagenberg? (A vocational IT school)

I discovered it in a study guide looking for IT schools. I had never heard about it before.

What do you like about Drobnik KG?

What’s great about Drobnik KG is that you are surrounded by other experienced people and I continuously learn new things. I appreciate it a lot that the company equips me with high-end hardware. I didn’t ever experience that in any other company before (and I have seen a few). I also like that we are going to conferences every now and then.

I am glad to be part of Drobnik KG and hope that this relationship will endure many more years.

Conclusions

Steve’s being with us for 4 years gives us a few hints about personality traits you need to possess to flourish in programming:

  • Frustration-tolerance: Don’t give up if a loose power cord threatens to wipe out all your work.
  • Aim to surround yourself with colleagues from whom you can learn.
  • If you are unhappy at your current employer, don’t be afraid to become a fledgeling new company’s first employee.
  • Being an employee in a small software company might ultimately be more rewarding than contracting because of the growth opportunities this yields.
  • Money is less important than long-term job satisfaction.

At Drobnik KG, we want to grow long-lasting client relationships where everybody wins. Junior developers have a chance to gain a foothold in the industry, Senior developers get to impart their knowledge on the Juniors and clients get the best of both: lower development costs but greater quality due to the Seniors being always at hand to help out the Juniors.

]]>
https://www.cocoanetics.com/2016/03/steves-senior-moment/feed/ 2 10183
Proportional Layout with Swift https://www.cocoanetics.com/2015/06/proportional-layout-with-swift/ https://www.cocoanetics.com/2015/06/proportional-layout-with-swift/#comments Sun, 21 Jun 2015 12:25:40 +0000 http://www.cocoanetics.com/?p=9714 Octavio asks:

I have an Autolayout challenge for you: I have a Square view which contains some images, labels, etc. We need that view to be full width on all iPhone screen sizes & resolutions.

The view is built at 320 x 320 (or @1x) and it is expected to scale proportionally for each and every other resolution and screen size. Basically, the view and all its elements should scale together, in unison, as if it was an image.

Thanks, Octavio, for a great question/challenge!

My first reaction was: “this is a problem I had solved previously!” But to make it a bit more interesting this time I am doing it with auto layout and Swift. We might learn something in the process.

When building the iCatalog framework – which was long before auto layout – we had the same problem with interactive zones on catalog pages where we would not know the final resolution. If you position a view in a superview, normally you have to specify origin and size relative to the superview’s coordinate system.

The solution then was to save origin and size in percent of the superview’s coordinates. This way you could easily multiply the percentage with the final width/height of the superview to arrive at the runtime coordinates.

Proportional Layout

The basic formula for any auto layout constraint is:

[view1] [attribute1] IS [relation] TO [view2] [attribute2] MULTIPLIED BY [multiplicator] PLUS [constant].

To model the same behavior as outlined above, for each view we need 4 constraints:

  1. left: [view] [Left] IS [equal] TO [superview] [Width] x percentage PLUS 0
  2. top: [view] [Top] IS [equal] TO [superview] [Height] x percentage PLUS 0
  3. width: [view] [Width] IS [equal] TO [superview] [Width] x percentage PLUS 0
  4. height: [view] [Height] IS [equal] TO [superview] [Height] x percentage PLUS 0

Each of the four values is always a percentage of the width or height of the superview. For example if the superview is {0,0, 100,100} and the view is {10,20,30,40} then the percentages would be {10%, 20%, 30%, 40%}.

Interview builder doesn’t have the ability to let us specify positions as a multiple of another view’s attribute. You can only specify it in points. This means we have to do this setup in code.

We’ll want to retain the ability to design the view in Interface Builder, but we need some code that will calculate the percentages and add the corresponding constraints to the view at runtime.

Enumerating Subviews

We need to apply the constraints to all subviews of a given view to make them scale proportionally to this outermost view. For that we need a method that will enumerate all views.

Wouldn’t it be nice if UIView had a method to do that where we could have a block be executed for each of the subviews in the entire tree? Let’s add it.

extension UIView
{
  func enumerateSubviews(block: (view: UIView) -> ())
  {
    for view in self.subviews as! [UIView]
    {
      // ignore _UILayoutGuide
      if (!view.conformsToProtocol(UILayoutSupport))
      {
        view.enumerateSubviews(block)
        block(view: view)
      }
    }
  }
}

This short function contains a few interesting lessons on Swift:

  • The method takes a block, so the parameter type for that is (view: UIView) -> (). It passes in the current view of the enumeration and returns nothing i.e. (Void) or ().
  • In iOS 8, the subviews array is still defined as [AnyObject]. So to save ourselves some explicit unwrapping later on, we can just force it to be an array of UIViews: [UIView]
  • iOS installs the top and bottom auto layout guides as _UILayoutGuide objects. Those are also considered subclasses of UIView so we cannot use the “if let as! UIView” pattern. But normal UIViews don’t conform to the UILayoutSupport protocol, so this trick lets us skip the layout guides in our enumeration

The innermost code recurses the function for the subview’s subviews and then calls the block. This will allow us to add the size and origin constraints to each of the subviews. So let’s get to the code for those now.

Removing Prototyping Constraints

Do you remember when Interface Builder would require you to always add all constraints? Later Xcode became smarter and would happily accept any IB layout. The difference came from IB tacitly adding as many constraints as would be required to nail down all positions and sizes.

Those prototyping constraints would clash with our proportional constraints, so we need to get rid of them – and only them.

extension UIView
{
  func removePrototypingConstraints()
  {
    for constraint in self.constraints() as! [NSLayoutConstraint]
    {
      let name = NSStringFromClass(constraint.dynamicType)
 
      if (name.hasPrefix("NSIBPrototyping"))
      {
        self.removeConstraint(constraint)
      }
    }
  }
}

We are again using the as! [Type] pattern to make sure we get a typed array of NSLayoutConstraint objects so that removeConstraint won’t complain. We convert the dynamicType to a string and if this class name has a prefix of NSIBPrototyping we remove it from the view.

Creating Size Constraints in Swift

Let’s first tackle the constraints for the size. As you will see its quite straightforward. The biggest annoyance for me when creating it was that Xcode does not have the ability to colon-align parameters.

extension UIView
{
  func addProportionalSizeConstraints()
  {
    // need to disable autoresizing masks, they might interfere
    self.setTranslatesAutoresizingMaskIntoConstraints(false)
 
    // there must be a superview
    let superview = self.superview!
 
    // get dimensions
    let bounds = superview.bounds;
    let frame = self.frame
 
    // calculate percentages relative to bounds
    let percent_width = frame.size.width / bounds.width;
    let percent_height = frame.size.height / bounds.height;
 
    // constrain width as percent of superview
    let widthConstraint = NSLayoutConstraint(item: self,
                                        attribute: .Width,
                                        relatedBy: .Equal,
                                           toItem: superview,
                                        attribute: .Width,
                                       multiplier: percent_width,
                                         constant: 0);
    superview.addConstraint(widthConstraint);
 
    // constrain height as percent of superview
    let heightConstraint = NSLayoutConstraint(item: self,
                                         attribute: .Height,
                                         relatedBy: .Equal,
                                            toItem: superview,
                                         attribute: .Height,
                                        multiplier: percent_height,
                                          constant: 0);
    superview.addConstraint(heightConstraint);
  }
}

The first line explicitly unwraps the view’s superview. This can – of course – be nil, which is why Apple made it an optional value. But since it does not make sense to call this method with no superview set we can leave it as that. We actually want this to throw an exception if we ever call this method while superview is still nil. This is our replacement for NSAssert which we would have used in Objective-C.

We calculate percentages for width and height based on the superview’s size and then add two constraints which set the view’s width and height as corresponding fractions. Next we’ll take care of the view’s origin.

Constraining Origin in Swift

Autolayout refuses to constraint Left or LeftMargin to be a fraction of another view’s Width. The workaround I found was to instead use the Right value of the superview. The other challenge is that Left cannot be ZERO times Right. In that case – if the percent value is 0 – we instead pin Left to the superview’s Left. The same is true for the vertical dimension.

extension UIView
{
  func addProportionalOriginConstraints()
  {
    // need to disable autoresizing masks, they might interfere
    self.setTranslatesAutoresizingMaskIntoConstraints(false)
 
    // there must be a superview
    let superview = self.superview!
 
    // get dimensions
    let bounds = superview.bounds;
    let frame = self.frame
 
    // calculate percentages relative to bounds
    let percent_x = frame.origin.x / bounds.width;
    let percent_y = frame.origin.y / bounds.height;
 
  // constrain left as percent of superview
  if (percent_x > 0)
  {
    let leftMargin = NSLayoutConstraint(item: self,
                                   attribute: .Left,
                                   relatedBy: .Equal,
                                      toItem: superview,
                                   attribute: .Right,
                                  multiplier: percent_x,
                                    constant: 0);
    superview.addConstraint(leftMargin);
  }
  else
  {
    // since a multipler of 0 is illegal for .Right instead make .Left equal
    let leftMargin = NSLayoutConstraint(item: self,
                                   attribute: .Left,
                                   relatedBy: .Equal,
                                      toItem: superview,
                                   attribute: .Left,
                                  multiplier: 1,
                                    constant: 0);
    superview.addConstraint(leftMargin);
  }
 
  // constrain top as percent of superview
  if (percent_y > 0 )
  {
    let topMargin = NSLayoutConstraint(item: self,
                                  attribute: .Top,
                                  relatedBy: .Equal,
                                     toItem: superview,
                                  attribute: .Bottom,
                                 multiplier: percent_y,
                                   constant: 0);
    superview .addConstraint(topMargin);
  }
  else
  {
    // since a multipler of 0 is illegal for .Bottom we instead make .Top equal
    let topMargin = NSLayoutConstraint(item: self,
                  attribute: .Top,
                  relatedBy: .Equal,
                     toItem: superview,
                                  attribute: .Top,
                                 multiplier: 1,
                                   constant: 0);
    superview .addConstraint(topMargin);
  }
}

Update: In my first published sample I didn’t yet disable the translation of autoresizing masks. But later I found that apparently some views – when created by IB – have autoresizing masks set which interferes with the proportional layout.

Next, let’s tie these methods together.

A Simple Test

The sample project – which you can find in my GitHub Swift Examples repo – has a view subviews put together in interface builder. The root view has a simulated size of 600 x 600 and all subviews are laid out relative to that. The effect we want to achieve is that all subviews should size and position proportionally if we rotate the view between portrait and landscape.

Test in IB

I couldn’t find an easy way to get the root view’s size after UIViewController had loaded it from the NIB. It always comes out at the correct resolution for the device, e.g. {0, 0, 375, 667} for iPhone 6. This would destroy our reference frame, so we need to restore it before enumerating through the subviews adding our proportional constraints.

The next auto layout pass will restore the correct root view frame and then also our proportional constraints will adjust the frames of all subviews.

class ViewController: UIViewController
{
  override func viewDidLoad()
  {
    super.viewDidLoad()
 
    // restore reference frame from IB
    self.view.frame = CGRect(x: 0, y: 0, width: 600, height: 600)
 
    self.view.enumerateSubviews { (view) -> () in
      // remove prototyping constraints from superview
      view.superview!.removePrototypingConstraints()
 
      // add proportional constraints
      view.addProportionalOriginConstraints()
      view.addProportionalSizeConstraints()
    }
  }
}

Note the syntax of the block we are passing into our subview enumeration function. In Objective-C we would specify the parameter list outside of the curly braces, like ^(UIView *view). In Swift the parameters are inside the closure and so Apple needed a way to separate the parameter header from the block code. The “in” keyword serves this function.

Inside the block we first remove any left over prototyping constraints, then we add the layout constraints for origin and size. Build and run and you will see:

Proportional Layout Demo

All squares we had in interface builder now get proportionally resized based on the dimensions of the outermost view. The one rectangle at the upper left side also resizes as expected.

Next we add an extra square view in IB so that we always have a square.

Layout Squared

We want the view to be a square and always be toughing the outside of the screen. This is what they call “aspect fit” if the touching sides are the ones that are closer together, or “aspect fill” if its touching the sides which are wider apart.

The tricky part here is that you need to work with two different priority levels. If auto layout cannot fulfil a lesser-priority constraint then it will ignore it. Mike Wolemer from AtomicObject wrote the article that explained this this me.

The Required priority constraints are:

  • View’s Aspect Ration should be 1:1
  • Center X on superview
  • Center Y on superview
  • View’s Width should be <= superview’s Width
  • View’s Height <= superview’s Height

The constraints with a lesser priority are:

  • View’s Width = superview’s Width
  • View’s Height = superview’s Height

Required constraints have a priority level of 1000, for the lesser priority you can use any lower value. The only constraint on the square centering view is the one for the aspect ratio. All others are attached to the root view.

Square Constraints

To add the constraints referencing the root view you CMD+Click on the root view and then the centering view. Click on the add constraints button and choose Equal Widths and Equal Heights.

For the greater-than constraints you do the same, but change the relationship in the constraint inspector. Make sure that you got the order of First Item and Second Item correct. If Superview is the first item, then the relation needs to be Greater Then or Equal.

First Item Second Item

Finally we need an outlet in ViewController.swift so that we can access the squareView. Then we change the enumeration to be only this view’s subviews. Et voilá!

Now in square glory

Bonus: Automatic Font-Adjusting

There remains one item that we didn’t touch upon: the font size in UILabels. The presented approach only adjusts the frames of views, but not their contents. For a UIImageView this is no problem if you set the View Mode to “Scale to Fill”. But the font size of a label would not automatically adjust to changes in the label’s frame.

There is no facility in auto layout which would allow us to tie the font size together with any length. But we are free to create a UILabel subclass that does exactly that.

Our FontAdjustingLabel stores its initial size and font when it awakes from NIB. This enables it to calculate an adjusted font size whenever its bounds change.

class FontAdjustingLabel: UILabel
{
  var initialSize : CGSize!
  var initialFont : UIFont!
 
  override func awakeFromNib()
  {
    super.awakeFromNib()
 
    // store values from IB
    initialSize = self.frame.size
    initialFont = self.font
  }
 
  override func layoutSubviews()
  {
    super.layoutSubviews()
 
    // calculate new height
    let currentSize = self.bounds.size
    let factor = currentSize.height / initialSize.height
 
    // calculate point size of font
    let pointSize = initialFont.pointSize * factor;
 
    // make same font, but new size
    let fontDescriptor = initialFont.fontDescriptor()
    self.font = UIFont(descriptor: fontDescriptor, 
                             size: pointSize)
  }
}

I needed to add the ! at the end of the instance variable definitions so that the compiler won’t complain that there is no init method which initializes it. Contrary to Objective-C, Swift does not automatically nil all ivars. Adding a ! or ? makes it an optional value and those do get initialized with nil.

Note the use of a font descriptor. This preserves all font attributes except the point size which we calculated based on the view’s current height relative to the initial height.

Conclusion

By answering Octavio’s question, we learned a few things about auto layout and how to set up constraints in Swift code. We created an extension to UIView, so that we could call these methods on any subclass of UIView.

We found that you cannot set up proportional constraints in Interface Builder. And the opposite is true for square layouts: first we thought that “aspect fit” wouldn’t be possible in Interface Builder, but it actually is, using constraints of different priority levels.

Finally, adjusting the font size is not possible with auto layout. But we can subclass UILabel so that it adjusts its font automatically. This way we have the auto layout system work together with manual adjustments in code to achieve the desired effect.

]]>
https://www.cocoanetics.com/2015/06/proportional-layout-with-swift/feed/ 3 9714
Core Image Barcode Erratum https://www.cocoanetics.com/2015/06/core-image-barcode-erratum/ https://www.cocoanetics.com/2015/06/core-image-barcode-erratum/#respond Wed, 17 Jun 2015 13:50:27 +0000 http://www.cocoanetics.com/?p=9686 Barcodes with iOSSince iOS 7, Core Image contains several generators for 2D barcodes. While I was writing my book Barcodes and iOS, only the CIQRCodeGenerator was documented. Apple’s standard policy is that classes which are not documented are to be considered off limites. Seeking clarification, I emailed an Apple evangelist and he confirmed that this is still the case.

So I mentioned the three other – undocumented – Core Image filters in the chapter about barcode generation, but cautioned the reader about their usage in app store apps: CIAztecCodeGenerator, CIPDF417BarcodeGenerator and CICode128BarcodeGenerator. At WWDC 2015, I learned that my assumption as well as the evangelist’s confirmation were incorrect.

I spoke with the Core Image engineering manager and he told me that there is an exception to the no-documentation rule for Core Image filters. You are alloc/init Core Image filter objects directly, but rather are using the filterNamed: method. The documentation team might lack behind in documenting certain filters, but that does not mean you cannot use them. He said that you can use the code below to find out which filters are available:

NSArray *b = [CIFilter filterNamesInCategory:kCICategoryGenerator];
NSLog(@"%@", b);

This means that these barcode generators are available, even when they are not (yet) documented:

  • CIQRCodeGenerator (iOS 7)
  • CIAztecCodeGenerator (iOS 8)
  • CICode128BarcodeGenerator (iOS 8)
  • CIPDF417BarcodeGenerator (iOS 9)

Technically, the private classes for these might have appeared in earlier iOS versions because iOS was using them internally for Passbook passes. But if filterNamesInCategory: method does not return them then they are off limits.

Who needs documentation anyway?

Should you wish to use a generator for which there is no documentation, you can find out about its input parameters with the handy attributes method.

CIFilter *filter = [CIFilter filterWithName:@"CIAztecCodeGenerator"];
NSDictionary *attributes = [filter attributes];
NSLog(@"%@", attributes);

The resulting dictionary tells you all you need to know:

  • CIAttributeClass is the class of the parameter
  • CIAttributeDefault is the default value if the parameter is omitted
  • CIAttributeMax is the maximum value for the parameter
  • CIAttributeMin is the minimum value for the parameter

Numeric values additionally provide CIAttributeSliderMin and CIAttributeSliderMax. If you are showing UI to configure this filter with a slider, those are the recommended limits.

Conclusion

There are more generators in Core Image that might be documented for a given iOS version. But if you can see them returned by this handy method then you may use them. Finding out the appropriate input parameters might take a bit of experimentation, but that is an easy exercise.

This is a fine example for why labs at WWDC are so valuable: it is the only place where you can talk to the guy in charge. After 4 months of my book being out, this is the very first errata.

]]>
https://www.cocoanetics.com/2015/06/core-image-barcode-erratum/feed/ 0 9686
Keychain Management Revamped https://www.cocoanetics.com/2015/02/keychain-management-revamped/ https://www.cocoanetics.com/2015/02/keychain-management-revamped/#comments Tue, 17 Feb 2015 10:43:42 +0000 http://www.cocoanetics.com/?p=9454 For the past several years I have been using an ugly hacked together class AccountManager in several projects for saving and retrieving generic passwords on the keychain. A couple of months ago I finally got around to replacing this with a well-designed thought-through component, DTKeychain, which works equally well on iOS and OS X.

You might wonder: why the hell is there a need for yet another new Keychain wrapper? For the simple reason that I like to understand what’s going on under the hood. Another reason is the fact that I am offering Non-Attribution Licenses for all my open source components and this makes it awkward if the components are referencing other peoples open source projects. I have no right to waive the attribution requirements for other people.

The impetus for creating DTKeychain was that for the open source iOS SDK for ProductLayer I needed to persist authentication tokens. Since both are available via CocoaPods the dependency is easily added.

Security.framework

With the previous AccountManager I tried to be too smart for my own good by having it do some unnecessary state management. Interaction with the keychain at the lowest level is done via multiple functions prefixed SecItem*. All of them return a status code.

So my goal was to have Objective-C equivalents to these functions following a different pattern we are used there:

- (NSArray *)keychainItemsMatchingQuery:(NSDictionary *)query 
                                  error:(NSError *)error

If this method returns nil then the error object is returned with the NSError object being filled in. In the case that truly no keychain items were found then an empty array is being returned.

I made this an instance method – as opposed to a class method – because this allows for the keychain class to be mocked in unit tests should you so choose. That’s much harder to do if all methods are class methods.

Keychains can hold different kinds of items but generally people only seem to be needing the Generic Password type. All keychain item fields are public except one: kSecAttrGeneric. This gets encrypted with a strong key that is tied to the user’s passcode.

OS X versus iOS

On OS X here also lies one major difference to iOS. On Macs you can query all fields of all keychain items without user interaction. But the first time to access the generic attribute value, there is a popup asking the user if he wants to permit that. This is why there is a separate function for querying that.

- (BOOL)retrieveSecuredDataForKeychainItem:(DTKeychainItem *)keychainItem
                                     error:(NSError *)error;

You never need to call this on iOS since there the retrieved items always contain the decrypted passwords. On OS X though, you need to call this method at that latest possible moment. Your app is halted while the prompt is showing.

Another difference concerns Sandboxing. iOS automatically limits access to keychains with the same application identifier prefix. This allows you to keep one keychain for multiple apps of yours.

If you run a wild card query for generic passwords on your Mac you will probably get hundreds of passwords, for websites, WiFi routers and many more. But fret not, this is not a security leak, since the user would have to approve access to the encrypted passwords for each app that is trying to access any item.

On most other keychain wrappers you cannot do such an enlightening wildcard query because they add a unique identifier (usually the application identifier) to all queries. The reason for this is to make keychain queries act the same one both OSes. I’d rather use a good qualifier for the service field (e.g. com.cocoanetics.MyService) to restrict queries to that.

Queries

A common pattern that I’ve seen in the code of all keychain wrappers I looked at related to the way of identifying keychain items. One way is by specifying a query. This is a dictionary with keys and values. Matching items are returned and/or affected by the function.

Those other wrappers would always use a query for the primary key. For generic passwords the key fields are kSecAttrAccount and kSecAttrService. This leads to the complexity of having to distinguish of old and new values for these key fields when those get modified.

I am only using these queries for doing wild card searches on the keychain. For subsequent updating or deletion of those items, I instead use the permanent reference kSecValuePersistentRef.

To query for all generic passwords for the foo service:

// get shared instance
DTKeychain *keychain = [DTKeychain sharedInstance];
 
// create a keychain query for generic passwords
NSDictionary *query = [DTKeychainGenericPassword
                       keychainItemQueryForService:@"foo" 
                                           account:nil];
 
// retrieve matching keychain items
NSError *error;
NSArray *items = [keychain keychainItemsMatchingQuery:query error:&amp;error];
 
if (!items)
{
   NSLog(@"%@", [error localizedDescription]);
}

For such an item changing the stored password is as simple as:

pass.password = @"different";
 
NSError *error;
if (![keychain writeKeychainItem:pass error:&amp;error])
{
   NSLog(@"%@", [error localizedDescription]);
}

This makes the usage of DTKeychain simple and intuitive, because it follows the same paradigms Apple is using for other methods.

In particular I would like to direct your attention to the _errorForOSStatus: method which creates properly worded NSError objects for the integer coming out of the SecItem* functions. This is also something I have not seen before elsewhere.

Conclusion

By not blindly copying code from previously existing keychain wrappers I was able to wrap my head around how the underlying keychain functions are really working. So can you if you look at my code.

Feel free to use DTKeychain in your own apps via Cocoapods or git submodule. This is my method of choice now for interacting with the keychains of iOS and OS X. Of course it has unit tests and appledoc-style documentation comments.

If you appreciate my work, please also check out recently released book.

]]>
https://www.cocoanetics.com/2015/02/keychain-management-revamped/feed/ 1 9454
Square-Cropping Images https://www.cocoanetics.com/2014/07/square-cropping-images/ https://www.cocoanetics.com/2014/07/square-cropping-images/#comments Tue, 22 Jul 2014 10:48:38 +0000 http://www.cocoanetics.com/?p=9228 Christian asks:

How would you – most elegantly – crop out the center square of an image, preserving the aspect ratio and output the image with a given size?

That’s a good question. There is a “classic” and a “modern” method to achieving this.

All drawing on iOS uses the Core Graphics framework. The initials of the name of this framework can be seen in many low-level drawing functions prefixed with “CG”. This framework is also know as “Quartz”, that that is mostly a marketing name as you don’t see it mentioned in Apple’s documentation.

Quartz does not know about Objective-C, as all its functions are C-functions. Common prefixes group similar functions, like CGContextSetInterpolationQuality and CGContextDrawImage both manipulate a CGContext entity. Quartz also does not know about ARC, anything that you create there you also have to destroy.

To make it easier to us developers UIKit adds an easier to use higher level layer on top of Quartz that abstracts away many of the headaches. One example of such a convenience is how you create a bitmap context to draw into. Orders of magnitude less code is needed via UIKit, than you would need with Quartz.

Bitmap Contexts

The “most elegantly” part of the question means that we won’t even bother with Quartz. Granted, there IS a method CGImageCreateWithImageInRect that would allow us to create a new CGImage from a smaller rectangle inside a source CGImage. UIImage is just a wrapper around CGImage.

In this case this method does not help us since we also have to scale the output image. Any time you wind up with a different size of image you have to employ a bitmap context. Graphics contexts are the basic canvas to draw onto. Bitmap contexts are a specialized variant of these optimized to create images from.

The usual steps are:

  1. Create a bitmap context fitting your output requirements
  2. Draw into the context, compose images on top of each other, knock yourself out
  3. Create a new image from the bitmap context
  4. Profit!

Granted you could use the CreateWithImageInRect first to cut out the center piece and then resize the output. But the resizing step would still require a bitmap context. The best way I know is to combine the two operations inside step 2 of the above list.

The code for this blog post is demonstrated in the SquareCrop example on my GitHub Examples repository.

I like to create a function for grouping together multiple operations that do not need any access to instance variables or methods of the class where I am using it. This allows me to move such a function to a more general place if I find that I would like to use it elsewhere as well. This pattern also communicates at a glance (to pros) that there exists no such dependency.

Square-Cropping Function

Here’s the content of my square-cropping function as you find it in the sample’s ViewController.m where it is used to crop an enclosed sample image. I added comments for every line to explain.

UIImage *squareCropImageToSideLength(UIImage *sourceImage,
                                     CGFloat sideLength)
{
   // input size comes from image
   CGSize inputSize = sourceImage.size;
 
   // round up side length to avoid fractional output size
   sideLength = ceilf(sideLength);
 
   // output size has sideLength for both dimensions
   CGSize outputSize = CGSizeMake(sideLength, sideLength);
 
   // calculate scale so that smaller dimension fits sideLength
   CGFloat scale = MAX(sideLength / inputSize.width,
                       sideLength / inputSize.height);
 
   // scaling the image with this scale results in this output size
   CGSize scaledInputSize = CGSizeMake(inputSize.width * scale,
                                       inputSize.height * scale);
 
   // determine point in center of "canvas"
   CGPoint center = CGPointMake(outputSize.width/2.0,
                                outputSize.height/2.0);
 
   // calculate drawing rect relative to output Size
   CGRect outputRect = CGRectMake(center.x - scaledInputSize.width/2.0,
                                  center.y - scaledInputSize.height/2.0,
                                  scaledInputSize.width,
                                  scaledInputSize.height);
 
   // begin a new bitmap context, scale 0 takes display scale
   UIGraphicsBeginImageContextWithOptions(outputSize, YES, 0);
 
   // optional: set the interpolation quality.
   // For this you need to grab the underlying CGContext
   CGContextRef ctx = UIGraphicsGetCurrentContext();
   CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh);
 
   // draw the source image into the calculated rect
   [sourceImage drawInRect:outputRect];
 
   // create new image from bitmap context
   UIImage *outImage = UIGraphicsGetImageFromCurrentImageContext();
 
   // clean up
   UIGraphicsEndImageContext();
 
   // pass back new image
   return outImage;
}

This code uses UIKit drawing for everything with one exception. To set the interpolation quality you have to grab the underlying CGContext (which UIKit manages internally for us) and use the C-function to set the interpolation quality.

Another reminder of Quartz can be seen by the fact that we have to call UIGraphicsEndImageContext before the end of the function. This causes UIKit to free up the memory of the CGContext it created for us.

This function also automatically uses the device’s display scale by specifying scale 0 in UIGraphicsBeginImageContextWithOptions. With this it gets the appropriate scale directly from iOS without us having to worry about it. You should never hard-code the scale because maybe one day Apple might ship devices that have a different scale than 2 (for the current Retina devices).

7 lines of code do some necessary calculations, 4 lines do the actual drawing and 2 lines are demonstrating directly tweaking a setting on the graphics context.

The sample demonstrates the use of this function:

- (void)viewDidLoad
{
   [super viewDidLoad];
 
   UIImage *image = [UIImage imageNamed:@"Image.jpg"];
   UIImage *squareImage = squareCropImageToSideLength(image, 300);
   self.imageView.image = squareImage;
}

Note that the 300 here are points, not pixels. The actual mapping from points to pixels should always remain the task of the operating system.

Conclusion

Nowadays there is very little reason to drop down to the Quartz-level for simple drawing operations. I can only think of one good reason to stick to Quartz: platform independence. You could – conceivably – write complex drawing operations as Quartz code and thus reuse it for both iOS and OS X.

The key takeaway of this post is that if you want a different output size than your source image you have to work with a interim bitmap context. This is the canvas to compose your graphics into before turning them into new UIImages.

Please don’t just copy/paste code you find on Stack Overflow into your apps. It will make your life much easier if you understand the distinctions I elaborated on in this article and if you stick with UIKit drawing where you can.

]]>
https://www.cocoanetics.com/2014/07/square-cropping-images/feed/ 5 9228
Should I switch to Swift? https://www.cocoanetics.com/2014/06/should-i-switch-to-swift/ https://www.cocoanetics.com/2014/06/should-i-switch-to-swift/#comments Mon, 09 Jun 2014 08:48:09 +0000 http://www.cocoanetics.com/?p=9166 Angelina asks:

I was very surprised when I heard about Swift.  I was curious what your thoughts are about Swift and phasing out Objective-C specifically since you are in the process of writing the Barcodes book.  Are you going to update your book to use Swift instead of Objective-C?

I mentioned previously that my book is feature complete. So the short answer is: No. The sample code is done and available to everybody who pre-ordered the early access version of the book.

So far I have identified a few things that are changing in iOS 8 which require minor modifications. Amongst them that Core Location now has two levels of location authorization, always or just when the app is in use. Apart from this I have not seen any advances in barcode technology (or related frameworks) in iOS 8 which would warrant new chapters or fundamental changes. If you want to build apps that leverage the built-in barcode scanner, you have to require iOS 7. And the chapters dealing with related technology also do. For example NSURLSession also requires it.

Then there is the timing about which iOS versions you should support if you are planning to release an app between now and the end of the year. When iOS 8 is released to the public, let’s assume October, you should continue to support iOS 7 for half a year, i.e. April 2015.  iOS is breaking adoption records with each new version, but you have to give your users some time to do it on their own pace. Since you have to support iOS 7 for barcode scanning, you might as well keep that as deployment target for this transition period.

On the other hand, if you are developing something to be released around the holiday season, you can start with iOS 8 as your baseline. The influx of many new devices being bought at that time favourably skews the number of your potential customers towards iOS 8. Here it depends if you want to use any of the new shiny APIs to more quickly build your app. But even if you do, the barcode scanning will work the same.

Lets make Angelina’s question a bit more broad:

“Does it make sense to migrate existing code to Swift?”

We have several closed and open sourced projects using Objective-C. There is nothing to be gained by rewriting everything in a new language. Apple lets you mix and match languages. If you add a new class to an existing project you may let yourself be tempted by the allure of Swift and use that for the implementation. Or even a new app is something that you can tackle in Swift right from the start to learn about it and be able to give feedback to Apple. I don’t see Swift replacing all of Objective-C development right away.

While Xcode 6 (and the contained LLVM compiler) are in BETA Apple reserves the right to make changes that might require tweaks in your source code. Another argument against rushing to Swift at this stage – especially for library vendors – is that there does not seem to be a way at present to keep methods private. Swift does not have headers, where you could only make visible the methods you want other developers to use. Which raises another question: how do you document libraries then? Right now I am using appledoc with specially formatted comments in my class headers.

If you must have HTML documentation which you can put on a web server you have to wait until appledoc supports Swift’s syntax. At this point you could have it scan the implementation files and it would find the /** */ comments, but it would fail to parse the method prototypes in Swift’s different syntax.

Conclusion

I’ll keep coding in Objective-C for the next few months and for existing projects. If I start a new open source project at a point when appledoc supports Swift, then I might look at doing the entire project in it. For existing apps I might try it for individual new classes, to get my bearings and get a feel for it. Or if there is a new app to be made, then I might try to do that entirely in Swift, too. But there is no reason to rush into a new relationship with a new language and abandon one you have grown to love over several years. Take your time to get to know each other first.

No question, Swift will eventually become the dominant language for developing on Apple platforms. But I foresee some remaining niches for where do do need to be able to drop down to C or assembly code. Any new technology that sees wide adoption always leaves some niches in existence where the replaced technologies dig in and remain in use. Just think of Vinyl LPs, CDs versus digital audio files.

]]>
https://www.cocoanetics.com/2014/06/should-i-switch-to-swift/feed/ 10 9166
Q&A: Seconds Since my Birthday https://www.cocoanetics.com/2014/01/qa-seconds-since-my-birthday/ https://www.cocoanetics.com/2014/01/qa-seconds-since-my-birthday/#respond Tue, 14 Jan 2014 14:06:00 +0000 http://www.cocoanetics.com/?p=8938 Julia asks:

How do I get Objective-C to display the number of seconds since my birth?

When you often gnaw on complex and frustrating questions – like I often do – it is rather refreshing to work out a good answer to such a simple question.

In Objective-C dates are represented by NSDate objects. Objects for arbitrary dates are created by means of NSDateComponents and an NSCalendar. The date components are essentially a structure where you specify a day, month and year number. The calendar then knows how to map these components to an actual date. Different calendars will have a different result, most of the western world is using the gregorian calendar which is the counting the years since the birth of Christ.

// create empty components
NSDateComponents *comps = [[NSDateComponents alloc] init];
 
// set the component values
[comps setYear:1997];
[comps setMonth:5];
[comps setDay:11];
[comps setHour:12];
[comps setMinute:12];
[comps setSecond:0];
 
// create a gregorian calendar for mapping
NSCalendar *g = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
 
// derive a date object from the calendar with these components
NSDate *dateofBirth = [g dateFromComponents:comps];

After this we have an NSDate object that the variable dateofBirth is pointing to.

There is an extra simple and a safer method to determine the number of seconds that passed since this point in time.

NSTimeInterval

Time intervals in Objective-C are represented by values of type NSTimeInterval. Those are not object, but rather a number. More precisely it is a double precision floating point value representing the an amount of seconds and second fractions. Internally dates are for the most part represented as the number of seconds that passed since an arbitrary reference date. Apple uses Jan 1st, 1970 00:00:00 for this for dates, and Jan 1st, 2001 in a few other cases.

NSDate has several instance methods that will give you the time interval between this date and another.

  • – [NSDate timeIntervalSinceDate:] – seconds between the other date and this date
  • – [NSDate timeIntervalSinceReferenceDate] – seconds between the first instant of 1 January 2001, GMT and this date
  • – [NSDate timeIntervalSince1970] – seconds between the first instant of 1 January 1970, GMT and this date
  • – [NSDate timeIntervalSinceNow] – seconds between this date and the current time

The last one of these instance methods sounds like what we want:

// get seconds from birth until "now"
NSTimeInterval secs = -[dateofBirth timeIntervalSinceNow];
NSLog(@"%d", (int)secs);

Note the use of the negation. The reason for this is that because “now” is a higher value than the “birth time” it would be negative.

You might think now that you could also use one of these methods to get the time interval between the birth day and an arbitrary date. Stop! Hold your horses!

Time intervals are not appropriate for this kind of date math. The reason being that this gives incorrect values for different time zones or if there are Daylight Savings Time switches between the dates. I explained the proper method for adding a time interval to a date in a previous post.

Date Math with NSDateComponents

Rather than using NSTimeInterval for answering the original question, you can also use NSDateComponents to do that. You see, this class is not only good for creating dates, but also to determine the amount of date units (e.g. seconds, days, months, et al) between two dates, again based on a specific calendar.

// create date object with current time
NSDate *now = [NSDate date];
 
// get seconds from birth time object until now object
NSDateComponents *diff = [g components:NSSecondCalendarUnit
                              fromDate:dateofBirth toDate:now
                               options:0];
NSLog(@"%d", (int)[diff second]);

We again use the previously created gregorian calendar und ask it to give us a new NSDateComponents object where we are interested in the “Seconds Calendar Unit”.

If you execute both methods in succession you see that the result is the same. At the time of this writing slightly more than 526.3 million seconds.

Conclusion

NSDateComponents – in combination with a calendar to base calculations on – is a versatile class. You can create NSDate instances for specific points in time. You can also use it to derive the difference between two date objects in an arbitrary calendar unit.

As an exercise try to modify the above to count the number of weeks or years between birthday and today.

]]>
https://www.cocoanetics.com/2014/01/qa-seconds-since-my-birthday/feed/ 0 8938
Updating CocoaPods https://www.cocoanetics.com/2013/11/updating-cocoapods/ https://www.cocoanetics.com/2013/11/updating-cocoapods/#comments Thu, 14 Nov 2013 08:03:53 +0000 http://www.cocoanetics.com/?p=8830 CocoaPods is being under constant development, and as the zero as major version number suggests, it is still in unstable status. So you should only be mildly surprised if calling the pod command outputs that a newer version is available. Here are some tricks for updating.

So when do for example following a pod repo update command:

CocoaPods Update Available

You can check your current version:

pod --version
0.28.0

Since CocoaPods is a ruby gem you can update it, and all other installed gems, just by:

sudo gem update

There will probably lots of loading and installing, but at the end you should see:

...
Fetching: cocoapods-core-0.28.0.gem (100%)
Successfully installed cocoapods-core-0.28.0
Fetching: cocoapods-0.28.0.gem (100%)

CHANGELOG:

## 0.28.0
[CocoaPods](https://github.com/CocoaPods/CocoaPods/compare/0.27.1...0.28.0)
• [CocoaPods-core](https://github.com/CocoaPods/Core/compare/0.27.1...0.28.0)
• [CLAide](https://github.com/CocoaPods/CLAide/compare/0.3.2...0.4.0)
...

In general this is all it should take. Users on Mavericks might need something extra in case they see errors coming out of the above or gem update refusing to update anything.

On OS X 10.9 you might have to install the Xcode command line developer tools, those are a prerequisite for the whole Ruby shebang to work.

The fastest method to install them, thanks to yanzv for pointing this out.

xcode-select --install

Installing Command Line Developer Tools

 

Curiously I didn’t need this on my iMac, but I did on my MacBook Air. Both are running Mavericks.

]]>
https://www.cocoanetics.com/2013/11/updating-cocoapods/feed/ 8 8830
Writing a Book https://www.cocoanetics.com/2013/10/writing-a-book/ https://www.cocoanetics.com/2013/10/writing-a-book/#comments Wed, 16 Oct 2013 11:48:01 +0000 http://www.cocoanetics.com/?p=8784 A couple of months ago a publisher contacted me about writing a book. I have written a lot in my lifetime, blogging in general on my German-language personal blog and later on my Cocoa development blog Cocoanetics. But of course I’ve never written something spanning more than a couple of pages.

Like everybody who likes to write I’ve toyed with the idea, but not knowing about what is involved in creating a technical book I shied away from it. I was assuming that all those book authors have to take time off their normal jobs for writing. I couldn’t imagine exclusively writing for 6 months and not having time for my regular development interests.

But then there was this contact who took the time to walk me through the initial steps toward my first book contract.

I’d like to write down what I think I understood so far about the process. I found that this is a good way for me to process new events. Also maybe somebody else finds it interesting considering also authoring a book.

Book Size

There appear to be two kinds of technical books, full-size and half-size. Full size books are between 400 and 600 pages, half size 200 to 300. It seems to me that most technical books are half size, unless they are about a whole framework or technology, like Core Audio.

My publisher was looking for a half size offering. Being full off … ideas, I was able to present 3 suggestions for topics that I felt would make for a nice half size book. All of this we discussed over the phone. He asked me which of these ideas I preferred and so I went with my favorite, though I am keeping the other two stored away at the back of my head.

Filling that many pages seems daunting at first. I did have a relatively clear idea what kind of content would fit with my chosen topic, but I had to structure them somehow. So I draw a 1-page mind map of the book. Sorry for not including a screenshot here, but I don’t want to discuss the book on my blog until it is well under way.

Proposal Review

Out of my mind map I furnished a Table of Contents (TOC) and wrote a 2-page book proposal.

Such a book proposal consists of these questions which you should answer with a couple of sentences each:

  1. Proposed Book Title
  2. About the Author(s)
  3. Proposal Summary
  4. About the Topic
  5. Book Description
  6. Competing or Comparable Sources
  7. Readers/Market
  8. Book Size and Illustrations
  9. Tentative Table of Contents with Annotations
  10. Contact Information

It is basically a formalized pitch. The tentative TOC I created in Pages based on my mind map which showed the main chapters already. The Book Size and Illustrations are supposed to be estimates for the number of published pages, the number of figures and the number of code listings.

Publishers probably receive a large number of such proposals and to find out the ones that show the most promises they send out the proposal plus TOC to around 10 people from the tech industry who are supposed to review the proposal and give feedback.

Of those 10 reviewers 8 returned the questionnaire and I got to read these as well. It was fun to see a few people amongst the viewers that I had had a passing encounter on Twitter before. All these reviews where generally very favorable, with only one being slightly critical about the scope of one chapter I had proposed.

Revising the Table of Contents

My proposal TOC did have all names of Apple Frameworks underlined because I figured that somebody looking at the TOC might get a feeling that there was more interesting content if it was clear which section to turn to for specific technologies.

The person dealing with me in lieu of the publisher was a so-called Acquisitions Editor aka Commissioing Editor. That’s the job title for somebody whose job it is to find authors and find proposals that make sense for the portfolio of the publisher.

Though at the time I didn’t know that those where not one and the same. So it came to me as a surprise when this person told me that he needed a revised TOC to present to the publisher. He told me that I should remove all references to Apple frameworks or names of technology because the publisher wouldn’t understand those.

So I produced a first revision 1.1 according to his wishes. Another big difference was that I was asked to follow a certain structure for each chapter.

  1. Chapter Intro
  2. Example Intro
  3. Example Walkthrough
  4. Explain Example
  5. Other Related Info
  6. Chapter Summary

So basically each chapter was supposed to be a sample app with the sections following the above pattern. I let myself be guided by this, since I am thankful for any kind of guidance I could get been a novice. But to make it sound a bit more interesting I had to put a personal touch on it and invented some very fancy section titles.

Generally a book is structured in Parts, Chapters and Sections. A half size book probably can do without parts that group multiple chapters. My proposal TOC had had 5 chapters with the last one being multiple app examples. With the examples now being elevated to being center pieces for the individual chapters I eliminated this extra chapter, and so version 1.1. had only 4 chapters with the last one having two examples.

A while later I heard back, it went well, but there was some critique related to my creative section titles. Also a second revision of the TOC was asked for, this time re-adding the names of Apple Frameworks. So my initial hunch was correct that people would want to see these in an iOS-themed tech book.

On the phone we went through the TOC one more time, cleaning it up further. My original structure was resting on the general pillars Intro, Input, Output, Interpreting and Examples. I was somewhat in love with that, mostly because it was my own idea. But it is dangerous in become too infatuated with your own ideas.

So I finally gave in to, added a new chapter on an additional Apple technology which is very prominent of late. And I broke up the fourth chapter in two. Admittedly this rounded off the TOC very well, resulting in 6 chapters of about equal size.

Version 1.2 of the TOC went back to the publisher and then nothing happened for a month. When I inquired it turned out that my email had gotten lost. This teaches us novice authors that you should never assume that the ball is out of your court. If you don’t hear back for too long it does not hurt to send of an email asking why there was no response.

Book Contract Preproduction

A short while afterwards I received the coveted response, the subject title beginning with “Contract Offer: <Your Book Title>”

At this point there is still some more planning work necessary. In order to furnish a contract the publisher requested that I provide:

  1. Contact Info
  2. Estimated Page count and number of figures
  3. Estimated Milestone Dates for:
    • TOC
    • Writing Sample
    • Chapter 1
    • 1/3 Milestone
    • 2/3 Milestone
    • 3/3 Milestone

When I asked why there was so much obsession on the TOC the editor told me that a good one makes a world of difference on the quality of the outcome. Especially on technical books the TOC probably also changes slightly as you start working on the actual text content. But having a general map in place gives you a feeling of structure to plug stuff into, as opposed to floating in thin air.

While being somewhat tedious and boring I found the first benefit of having spent some thought on it that it allowed me to do a good estimate for the page count and number of figures. I just copied my TOC into Numbers and distributed the initial estimate on the sections. Sections like a summary would not get any illustrations and very few pages. Other sections giving an introduction to a necessary Apple framework would get many more pages and also more illustrations.

Again I was very thankful for the guidance I got, estimating about 30 pages per chapter and about 5 figures per chapter. You can have even more figures for something dealing with visual content. Source code listing counts as text, not figures.

The writing sample typically is a 10-page section that you pick out with a professional editor that it maybe a bit harder than other sections. I don’t yet know the actual purpose except to prime a newbie author on how to approach the writing in terms of style and work flow.

The next thing was one that I had the most reservations about: How much time should I plan for finishing those mile stones?

Show me the Money!

In the experience of the editor writing a book is doable next to a full time day job. Most authors, once they get going, can turn a new chapter every 2-3 weeks next to their full time day job.

I’m self-employed and since I feel passionate about this book I am pretty sure that I will be devoting enough time on the book to get it done. So I put down the final milestone about 4 months in the future, adding some buffer for the first few items so that I have room to “get up to speed”.

From what I learned in the process you cannot live off the royalties of your first book. It all depends of how many copies it will be selling, you don’t generally get paid for the writing itself. Rather you receive 10% royalties on the book price. That is for paper books, purely electronic versions can pay higher percentages. But in my case I definitely want my first book to be published in paper form.

The standard for the first edition of a new book is 10% royalties with a $2,500 advance. Of this half is paid at the 1/3 milestone, the remainder when the book goes into final production.

Hopefully the book sells really well, but if it doesn’t then the advance is all you get. Let’s say I work 3 weeks for each of the 6 chapters, 20 hours per week. That are 360 hours for which you receive no less than $2,500. This calculates to about $7 per hour, less than a tenth of what I am making if I am doing iOS development consulting.

I will definitely not get rich from this, but I’ll nevertheless do it. My economic circumstances of the next few months will allow me to carve of enough time each week to progress on the book. And the final reward – being a published author – is something that excites me a lot.

Conclusion

I happen to have a topic that I am passionate about these days and so it was an incredible stroke of luck to be contacted by somebody who would want to contract me to write a book on this topic.

You cannot hope to earn a lot of royalties from a single book, but – in contrast to my previous fears – writing a book is actually achievable even next to having to work for your money. As a general rule book authors have a full time day job next to writing. So if you think about writing a book you have to be able to find the time next too your livelihood to push forward your writing.

Those are the facts as I see them at this point before my actual journey has even begun. I’m interested to hear from my book-writing colleagues where they had experiences that differ from what I described.

]]>
https://www.cocoanetics.com/2013/10/writing-a-book/feed/ 11 8784
Don’t Cross The Streams https://www.cocoanetics.com/2013/10/dont-cross-the-streams/ https://www.cocoanetics.com/2013/10/dont-cross-the-streams/#comments Mon, 14 Oct 2013 09:44:01 +0000 http://www.cocoanetics.com/?p=8773 Like most people I could get buy blissfully without dealing too much with Auto Layout. But there are layout-heavy scenarios where you start having the feeling that they might be much easier to solve using auto layout than by setting autoresizing masks (aka “struts and springs”).

One such example is the layout of controls in an inspector panel where I laid out the controls distanced from each other with layout constraints in Interface Builder. Architecture-wise I am using such an “inspector palette” in a DMInspectorPalette which gives me several collapsible sections. These are contained in a NSTabView (using DMTabBar as header) to get multiple inspectors laid out like in Xcode. And these are the right-most view in an NSSplitView to allow resizing of the inspector panel.

I was having some issues with that beginning with 10.9 which I’d like to document here.

Beginning with OS X 10.9 I started to see enormous tearing on something that was working without problems on earlier Mac OS versions. It’s as if the subviews of the tab view would get their frames updated much later than the split view divider was being moved. Funny thing: this only occurred on my 2 year old MacBook Air, not only my 27″ iMac, both are running the GM of 10.9.

Also I was not able to record the issue occurring with Quicktime, while I was recording the panel was always behaving perfectly.  So I recorded it with my iPhone. Look at “Info” how that lags behind the gray bar above it.

Tearing

On OS X and iOS alike Auto Layout is off by default and gets enabled as soon as any subview in the window’s hierarchy has a layout constraint added. That could either be by adding a subview loaded from Interface Builder that has the Auto Layout checkbox checked, or by adding a constraint to a view in code. It says so in the docs.

Let me repeat that: add a single constraint and the entire window will be using Auto Layout. This is true for both iOS and OSX.

Auto Layout Emulates Struts & Springs

Normally you should not notice a difference because the OS automatically translates all autoresizing masks into equivalent layout constraints that behave exactly the same. Though as my example has shown the timing between both systems might be slightly different.

In my code the frame of the Info panel was set via setFrame: whereas the gray tab bar with icon was set via autoresizing mask. Adding the panel contents – which is using Auto Layout in IB – moved the tab bar to be using equivalent layout constraints. It seems to me that one a sufficiently fast Mac you should not see a difference, but in my case I’m redrawing a large page image on every pixel the divider is moved and that stressed my Intel GPU sufficiently that it didn’t get around to calling setFrame: often enough.

Interestingly I found that removing the setFrame and setting autoresizing masks on both the bar and the content view did nothing to improve the tearing. Only converting it to be using Auto Layout fixed the problem.

To make the adding of a total of 8 constraints a little easier I created a helper method.

- (void)addLayoutConstraintsForSubview:(NSView *)subview  edgeInsets:(NSEdgeInsets)edgeInsets
{
   NSParameterAssert(subview);
   //NSAssert(subview.superview == self, @"Can only pin a direct subview of the receiver");
 
   // subview cannot have autoresizing mask, that would interfere with these
   subview.translatesAutoresizingMaskIntoConstraints = NO;
 
   NSMutableArray *tmpArray = [NSMutableArray array];
 
   if (edgeInsets.left >= 0)
   {
      // subview's left is x points from superview's left
      NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0 constant:edgeInsets.left];
      [tmpArray addObject:constraint];
   }
   else
   {
      // subview's left is x points from superview's right
      NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0 constant:edgeInsets.left];
      [tmpArray addObject:constraint];
   }
 
   if (edgeInsets.right >= 0)
   {
      // subview's right is x points from superview's right
      NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0 constant:-edgeInsets.right];
      [tmpArray addObject:constraint];
   }
   else
   {
      // subview's right is x points from superview's left
      NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0 constant:-edgeInsets.right];
      [tmpArray addObject:constraint];
   }
 
   if (edgeInsets.top >= 0)
   {
      // subview's top is x points from superview's top
      NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:edgeInsets.top];
      [tmpArray addObject:constraint];
   }
   else
   {
      // subview's top is x points from superview's bottom
      NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0 constant:edgeInsets.top];
      [tmpArray addObject:constraint];
   }
 
   if (edgeInsets.bottom >= 0)
   {
      // subview's bottom is x points from superview's bottom
      NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-edgeInsets.bottom];
      [tmpArray addObject:constraint];
   }
   else
   {
      // subview's bottom is x points from superview's top
      NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:-edgeInsets.bottom];
      [tmpArray addObject:constraint];
   }
 
   [self addConstraints:tmpArray];
}

This method allows me to express a subview’s constraints relative to its superview in terms of edge insets. Positive values means a distance from the corresponding edge. Negative values mean the opposite edge.

So for the top bar which is 22 points high but otherwise follows its superview we can specify:

[self addLayoutConstraintsForSubview:_tabBar edgeInsets:NSEdgeInsetsMake(0, 0, -22, 0)];

The third value is negative in the bottom slot, which means that the bottom is 22 points from the top of the superview.

For the content view we specify:

[self addLayoutConstraintsForSubview:_tabView edgeInsets:NSEdgeInsetsMake(22, 0, 0, 0)];

We established before that having layout constraints on any view causes all autoresizing masks to be converted to layout constraints as well. This would mean in this case that we could end up with conflicting constraints and so we need to disable this automatic translation.

// subview cannot have autoresizing mask, that would interfere with these
subview.translatesAutoresizingMaskIntoConstraints = NO;

If you begin to adopt Auto Layout in code you probably have seen the kind of exception this produces if you have your own constraints conflict with autoresizing-constraints:

Auto Layout Exception

In this example the NSLayoutConstraint line is our own, the two NSAutoresizingMaskLayoutContraint are such automatically translated constraints.

I produced the above exception by setting a subview’s autoresizingMask to flexible height and width and then adding a constraint limiting the width to 30. Autoresizing Mask Layout Constraints are installed with a priority level of 1000 (required), the same as when you don’t specify a priority for your own level.

Thus if we modify our own constraint’s priority to 999 this exception is no longer occurring, since 999 is no longer required, but a very strong suggestion.

Interpreting NSAutoresizingMaskLayoutContraint

Those system constraints participate in the Auto Layout system like other constraints, but they are specialized to be able to constrain multiple layout attributes using only a single layout constraint object.

I’ve often wondered as to how to read the log output, Stack Overflow user jrturton figured it out.

“…the logging format is pretty straightforward.

  • h= or v= indicates that we are talking about contraints in the horizontal or vertical direction.
  • – indicates a fixed size
  • & indicates a flexible size
  • The order of symbols represents margin, dimension, margin

Therefore, h=&-& means you have flexible left and right margins and a fixed width, v=-&- means fixed top and bottom margins and flexible height, and so forth.”

Conclusion

The obvious conclusion if what this article derived its title from: Don’t cross the streams.

Apple does make it very simple for us to migrate to Auto Layout by automatically translating autoresizing masks to internal constraints. And for the most part this works without you even noticing that something differently is happening.

But there are cases – like I have demonstrated here – where this switching to Auto Layout has problems with some custom views which still have an overwritten setFrame: method. If you start seeing such weird issues you know that it is time to completely move to using layout constraints.

For the longest time I wondered how I could get the same behavior in code as you get when checking the Enable Auto Layout checkbox for a view in Interface Builder. My eyes also got opened by the information that Auto Layout is off by default and will get enabled for the entire window as soon as there is a single layout constraint anywhere.

Put simpler: there is is no such equivalent in code. This switch only tells IB to create layout constraints at design time. And once this view is added to a window, it will enable Auto Layout for everything.

]]>
https://www.cocoanetics.com/2013/10/dont-cross-the-streams/feed/ 5 8773
-fobj-arc is not supported on platforms using the legacy runtime https://www.cocoanetics.com/2013/10/fobj-arc-is-not-supported-on-platforms-using-the-legacy-runtime/ https://www.cocoanetics.com/2013/10/fobj-arc-is-not-supported-on-platforms-using-the-legacy-runtime/#comments Wed, 09 Oct 2013 08:17:17 +0000 http://www.cocoanetics.com/?p=8765 The Cocoanaut asked on Twitter:

“Does anybody know what this error means? (compiled on a white MacBook with 10.7.5 and Xcode 4.6.3)”

He attached this screenshot:

-fobjc-arc not supported

I’ve been seeing this error quite often lately and so I’d like to document my answer for posteriority.

With each Xcode update it makes a few more or less helpful suggestions as to what settings you might be wanting to change. It saves the last Xcode version where it performed this check in the project file so that it will not bother you until the next Xcode update.

Xcode 5 suggests to remove the Architectures setting. “This will remove the setting and allow Xcode to automatically select Architectures available for the active platform and deployment target”

Remove Architectures Setting

Of course we want the warning to go away so we let Xcode perform the changes. Thanks Xcode for helping me improve my project!

One change in the project is that the LastUpgradeCheck value gets set to 0500.

LastUpgradeCheck

The second change is to remove the ARCHS setting from all build configurations.

Remove ARCHS

The warning is gone and we go on coding and debugging in Xcode 5 not suspecting that this change will be causing a problem on our build server.

Build Server Fail

I performed this suggested update on several apps and projects but when the continuos integration build kicked in it suddenly started to fail. I opened the same project that I did the changes to capture the above screen shots in Xcode 4.6 and when trying to build it it fails:

i386 PCH build failing

Hidden in the arguments for the ProcessPCH build step you can see that Xcode 4 seems to think that we would like to build this for i386 aka 32 bit.

If you create a new Mac project from template then Xcode 4.6 set the ARCHS to $(ARCHS_STANDARD_64_BIT) aka “64-bit Intel”, regardless of the ARC setting. The default setting in Xcode 4.6 for ARCHS is $(ARCHS_STANDARD_32_64_BIT) aka “Standard (32/64-bit Intel” and this is also the value that Xcode 4.6 assumes you mean if the ARCHS setting is no longer present (because Xcode 5 removed it).

32 Bit apps on Mac generally use the Objective-C 1.0 runtime, aka Legacy Runtime. This runtime version does not support ARC. Put differently, ever since you adopted ARC in your Mac apps you’ve been building for 64-bit only and now the removal of the ARCHS causes Xcode 4 to try and build for 32-bit as well.

On Xcode 5 the default value for Architectures has changed to $(ARCHS_STANDARD) aka “Standard Architectures (64-bit Intel) (x86_64)”. This is the reason why when building this Mac app with Xcode 5 you never see a problem, since it only tries to build for 64-bit.

Conclusion

Getting any build message mentioning a legacy runtime means that your compiler is trying to build a combined 32- and 64-bit application. To fix that you’ll have to either restore the ARCHS to a value that only allows 64-bit output, or you update your Xcode to version 5.

You can do so without getting the upgrade warning, because the LastUpgradeCheck will remain on Version 5 and thus remain dormant until the next Xcode update.

]]>
https://www.cocoanetics.com/2013/10/fobj-arc-is-not-supported-on-platforms-using-the-legacy-runtime/feed/ 7 8765
TopLayoutGuide 97 Pixels?! https://www.cocoanetics.com/2013/09/toplayoutguide-97-pixels/ https://www.cocoanetics.com/2013/09/toplayoutguide-97-pixels/#comments Sat, 28 Sep 2013 09:25:40 +0000 http://www.cocoanetics.com/?p=8687 When implementing iOS 7 support for a client’s app I got a result that might stump even seasoned Cocoa programmers.

On iOS 7 views generally go behind translucent bars. To still get your views aligned correctly – when creating them in code – you have to get the responsible view controller’s top and bottom layout guides.

Those get set sometime before viewWillLayoutSubviews and I found it useful to add a viewInset property to the view controller’s base view. Setting this would setNeedsLayout and then you can rearrange the subviews according to the new insets in layoutSubviews.

Though this is not the riddle I want to talk about. Consider the following code – imagine if you will – by an engineer who is trying to code it such that you can still build it with the iOS 6 SDK.

- (void)viewWillLayoutSubviews
{
   [super viewWillLayoutSubviews];
 
   CGFloat topInset = 0;
 
   if ([self respondsToSelector:NSSelectorFromString(@"topLayoutGuide")])
   {
      id topLayoutGuide = [self valueForKeyPath:@"topLayoutGuide"];
      topInset = (CGFloat)[topLayoutGuide length];
   }
 
   // do something with topInset
}

You can create a Single View iOS app and paste the above code into the ViewController.m file to see the effect yourself.

Ok, now the question: running on iOS 7, what will the value be in topInset? And why?

97 Pixels?!

The answer is 97. And this is – of course not the amount we were looking for. Since we don’t have any top tool or nav bars the correct answer is 20 occupied by the now-transparent status bar.

Cédric Luthi sheds some light on this:

Since topLayoutGuide is typed as id, the return type of the length message is guessed to be NSUInteger and the message is sent with the wrong ABI calling convention.

Try using your topLayoutGuide object actual class instead of casting the result to CGFloat.

id<UILayoutSupport> topLayoutGuide = [self valueForKeyPath:@"topLayoutGuide"];
topInset = [topLayoutGuide length];

Calling it like this we get the correct value. Having a protocol as part of the variable definition is key since this allows the compiler to know that the return value type to be expected is CGFloat. Without this the compiler guesses which of the multiple length methods you might be referring to, and in this case it guesses wrong.

There is a compiler warning that you can enable, which is disabled by default because historically Apple’s code was full of such weak typing hazards.

Enable Strict Selector Matching

Building with this setting enabled we get an interesting warning:

Multiple Selector Warning

Indeed! NSString’s length is being used instead of the length property defined in the UILayoutSupport protocol.

If we enforce the user of the correct length method via the protocol we solve the problem. The above is only compilable with iOS 7 SDK (where UILayoutSupport is defined for the first time), but this protocol is very simple:

/*
 UILayoutSupport protocol is implemented by layout guide objects
 returned by UIViewController properties topLayoutGuide and bottomLayoutGuide.
 These guide objects may be used as layout items in the NSLayoutConstraint
 factory methods.
 */
@protocol UILayoutSupport <NSObject>
@property(nonatomic,readonly) CGFloat length;  // As a courtesy when not using auto layout, this value is safe to refer to in -viewDidLayoutSubviews, or in -layoutSubviews after calling super
@end

BTW it is not entirely accurate that the value is only safe to refer to in -viewDidLayoutSubviews. If you had to wait until that time you had to always do two layout passes, one without the guides set and one with the insets. But it turns out that you can already retrieve the correct value in -viewWillLayoutSubviews. This way you can set up the insets before the first layoutSubviews will occur.

If we don’t want to compile against iOS 7 SDK, we can create our own protocol with the same property just so that the compiler will do the right thing with the stack parameters.

// above the @implementation
@protocol MyLayoutSupport <NSObject>
@property(nonatomic,readonly) CGFloat length;
@end

And there I was assuming that you can send any kind of message to an id-typed objects. Well, yes, you can and if the return values are also id then you have no problem like this. But if you expect a scalar (int, float) return value then you are asking for trouble, messaging ids.

Matt Gallagher wrote an article two years ago explaining this limitation of Objective-C’s weak typing in greater detail.

UPDATE: Damien DeVille, Software engineer from London UK, wrote a response to this article explaining this phenomenon a bit more in depth with some ARM assembly.

Conclusion

It is generally good practice to make sure that you coax ids into strong object types as much as feasibly. The new instancetype type helps with telling the compiler that this is a specific Class, not just any id. This avoids potential “unrecognized selector” crashes at runtime.

It might be a good idea to enable a couple of additional Xcode warnings, especially if you are looking to clean up an existing project or starting a new one. Strict Selector Matching might be a candidate for you.

When it comes to scalar return values there you definitely must go the strongly typed route. Either you can cast the id to a concrete object type, or if you cannot then you can at least define a protocol to tell the compiler what return type to assume.

]]>
https://www.cocoanetics.com/2013/09/toplayoutguide-97-pixels/feed/ 7 8687
Implicit IVAR Synthesis https://www.cocoanetics.com/2013/09/implicit-ivar-synthesis/ https://www.cocoanetics.com/2013/09/implicit-ivar-synthesis/#comments Sat, 07 Sep 2013 07:45:41 +0000 http://www.cocoanetics.com/?p=8640 Apple recently added the ability for Xcode to automatically create instance variables for you. This means you no longer need to add an @synthesize for each property you create.

But does it really do that always, or are there scenarios where no _ivar is needed? Are there situations wehre you do need an explicit synthesis? For example what about properties which are just passing through values to a sub-object?

I wanted to know, so I experimented a bit. I even filed a Radar with Apple for clarification which came back with a good explanation.

Let’s create a new class for our test.

@interface TestObject : NSObject
 
@property (nonatomic, copy) NSString *string;
 
@end

Having not added any @synthesize will still get an instance variable _string be generated for us. To prove this, we add a method that accesses it:

#import "TestObject.h"
 
@implementation TestObject
 
- (NSString *)description
{
   return _string;
}
 
@end

No compiler error so far, so _string indeed exists.

Let’s override the setter.

- (void)setString:(NSString *)string
{
   // don't accept nil
   NSParameterAssert(string);
 
  _string = [string copy];
}

The synthesize is inferred, Xcode simply assumes that we had written the following somewhere in the implementation (personally I prefer to have these at the bottom).

@synthesize string = _string

Note that if you specify the synthesize like in the olden days the compiler no longer accepts the _string:

@synthesize string;

This creates an instance variable that is also called string, which is inconvenient since that forced people to name they setter method parameters something like aString. Yuck!

Now let’s also overwrite the getter:

- (NSString *)string
{
	return _string;
}

And now something curious happens. This was the reason why I filed a Radar:

missing ivar

Like  anybody who never really gave much thought to this implicit mechanism I got confused by the sudden appearance of these build errors. Apple’s response to my inquiry explains it nicely:

Engineering has determined that this issue behaves as intended based on the following information:

This is correct behavior. Once both the getter and setter are provided no implicit storage gets created. When you need an ivar, you will need to use @synthesize.

If you have a readwrite property then you don’t get an implicit ivar if you overwrite both setter and getter. Does it make a difference if the property is change to readonly? Yes. For readonly properties you only have to override the getter method to prevent ivar synthesis.

Conclusion

Since I was used to supporting older Xcode versions with my open source frameworks like DTCoreText I still had the habit of explicitly defining all instance variables as well as adding an @synthesize property = _ivar line for each of them. This is why I didn’t benefit from or understand implicit IVAR generation until now. Honest mistake.

But working on apps that require more recent Xcode versions to build allows me to also save me some typing because I now know how implicit IVAR synthesis works. To summarize: For readwrite properties you get an _ivar if you don’t overwrite both the setter and getter. For readonly properties you only get an _ivar if you don’t overwrite the getter.

]]>
https://www.cocoanetics.com/2013/09/implicit-ivar-synthesis/feed/ 21 8640
Undefined Symbols https://www.cocoanetics.com/2013/07/undefined-symbols/ https://www.cocoanetics.com/2013/07/undefined-symbols/#comments Wed, 10 Jul 2013 08:48:02 +0000 http://www.cocoanetics.com/?p=8457 OC asks:

“I’m doing some Objective-C exercises from a Big Nerd Ranch book, and I’m getting these errors. I’m still pretty lost in terms of how to handle unexpected errors and stuff, so I would appreciate the help.”

I’m going into go into much greater depth here answering this question, because of “teaching a man to fish”, ya’know.

OC included this screen shot which depicts the error he was getting:

Undefined Symbols Linker Error
Building an app typically has 3 steps:

  1. Pre-Processing
  2. Compiling (into Object Code)
  3. Linking (Objects into a Binary)

Pre-Processing is the step where all these #define and #import are executed. The Compiler sees your source files thus preprocessed, so for example having imported a header tells it about the characteristics of the class the header of which you have imported. The compiling results in .o files which have references to classes and methods which are called symbols or symbolic links. When the Linker then joins all those object files into a binary (app or lib) it looks at those symbols and symbolic links and resolves these links to actually point to concrete classes and their methods.

The error on the screenshot comes from the linker as evidenced by the mention of “ld” (LLVM’s linker), “linker command failed” and the message “Undefined symbols for..”. This means that you got as far as step 3, because you probably have an import for the Logger class’ header so that the compiler does not complain in step 2. But you are missing the Logger.o object file from the linker step.

Most likely because it was not built during 2 because it is not a member of the target you are building. Another reason would be if you have the Logger class in an external static library (which is also just an archive of .o files) and forgot to add this to the linker build phase.

Getting “Undefined Symbols” means that you have to look for why the object code for the missing symbols was not available:

  • Do you have a Logger.m which is not part of your target? (does it have the check mark)
  • Do you have a static library which contains the Logger class? Is this missing from the Link with Libraries build phase?

Once you have provided the missing symbols the linker will be happy to to link it all together.

Next exercise, how I fix the following 82 linker errors in DTCoreText?

82 Linker Errors

If you look up “CTFont” in the documentation you find that these functions are part of the Core Text framework. So your next thought should be: “aha, the headers were found and this compiled, but the linker didn’t find the symbols.”

So, check in the frameworks group and what do you see?

CoreText.framework not part of target

Indeed, for this demonstration I removed the CoreText.framework from the Target membership of DemoApp. If we restore the checkmark there the build process finishes successfully.

Conclusion

You import a class header file so that the compiler knows which classes and method exist. You can only work with objects that it knows about and only call methods which are made public to the other code files via a header. Clang (the compiler) usually has no problem finding the header files because they are usually in your project folder.

But that does not mean however that ld (the linker) has the object code available for these classes. To have it you either need to have an implementation file (.m) as part of the compilation, as member of the target you are building.

Or – if you use static libraries – then the object file (.o) produced as part of the static library’s compilation will be contained in the library archive (.a). For the latter case this static lib needs to be part of the linker phase to have it’s objects be linked into your app.

If you understood the above then you will never be stumped by a linker error. Instead you immediately go search for the .m or lib containing the missing symbols and add that to your target.

]]>
https://www.cocoanetics.com/2013/07/undefined-symbols/feed/ 5 8457
DTCoreText: Centering an Image https://www.cocoanetics.com/2013/04/dtcoretext-centering-an-image/ https://www.cocoanetics.com/2013/04/dtcoretext-centering-an-image/#comments Sun, 07 Apr 2013 13:09:18 +0000 http://www.cocoanetics.com/?p=7991 Amy Worall asks:

How do I centre an image in DTCoreText? I’m working with attributed strings not HTML. Any sample code?

In this blog post will answer this.

DTCoreText consists of multiple parts: tools for converting between HTML and attributed strings, a custom layout engine doing the “frame setting” and (on iOS) several UI classes for displaying those attributed strings.

For most scenarios you would want to simply pass in some HTML data and display that, but Amy’s use case seems to forego this step. And there is nothing wrong with skipping directly to putting together an NSAttributedString. As long as you use the same attributes that the HTML parser would put in there the result should be identical.

Amy is trying to get a divider image centered amongst the text. This should be a simple exercise, but somehow it comes out as being off center. Looking at the sample code she provided didn’t yield any clues as to what could be reason for this.

BG7rJiaCMAE8GUy.png-large

My first thought when seeing this was that this has to be a bug in DTCoreText. Feelings of Panic starting to rise.

Try it in the Demo App

So my search for the cause of the off-centering began with the DTCoreText demo app. I like to make sure I have the latest version of DTCoreText (and submodules) cloned and then I try to find a place where I can test the text.

If I have HTML that does not seem to come out right, then I paste it into the CurrentTest.html which is the last menu option in the demo’s menu of snippets.

So the first test I am doing is to see if maybe centered paragraphs are broken somehow. In HTML you can switch to centered paragraph styles with the <center> tag or with the equivalent CSS text-align attribute. Images that are contained in the app bundle can be referenced without any path.

<html>
<head>
<body>
<center><img src="Oliver.jpg" width="100" height="100"></center>
<p>
Lorem ipsum dolor sit amet, ...
</p>
</body>
</html>

Push the “Debug Frames” button to have DTCoreText draw additional backgrounds behind the glyph runs, the frame outline. There is also a dashed centering line.

iOS Simulator Screen shot Apr 7, 2013 2.10.22 PM

 

We can see that the image is centered on the centering line. At least we know that the problem must lie elsewhere.

Inspecting the Chars view shows that the image paragraph consists of the Unicode Object Placeholder @”\ufffc” character and a newline (code 10). The Ranges view shows that the placholder character has a DTTextAttachment attribute, a run delegate attribute as well as a paragraph style with alignment 2 for centering.

The placeholder character is not being displayed itself. Instead CoreText calls the run delegate to get the dimensions from the text attachment. The run delegate asks the DTTextAttachment for Ascent, Descent and Width to be reserved so that the image has enough space to fit. Since the run delegate is a set of C-functions it has no context from being in the scope of an object. For this purpose there is a context parameter in which we pass a pointer to the text attachment.

The text attachment object and the run delegate always exist retained by the same attribute range this is possible, even under ARC.

And Now in Code

Amy provided the following gist of the code she’s been experimenting with. With what I explained above, can you spot the problem?

NSMutableParagraphStyle *centredPS = [[NSMutableParagraphStyle alloc] init];
centredPS.alignment = NSTextAlignmentCenter;
 
NSMutableAttributedString *attributedStringBuilder = [NSMutableAttributedString new];
 
DTTextAttachment *attachment = [[DTTextAttachment alloc] init];
UIImage *image = [UIImage imageNamed:@"divider"];
attachment.contents = image;
attachment.contentType = DTTextAttachmentTypeImage;
attachment.displaySize = image.size;
NSMutableDictionary *newAttributes = [NSMutableDictionary new];
[newAttributes setObject:attachment forKey:NSAttachmentAttributeName];
[newAttributes setObject:centredPS forKey:NSParagraphStyleAttributeName];
[attributedStringBuilder appendAttributedString:[[NSAttributedString alloc] 
                         initWithString:UNICODE_OBJECT_PLACEHOLDER attributes:newAttributes]];
 
[attributedStringBuilder appendString:@"\n"];
 
// then append all our normal paragraphs of text.
// This is eventually given to a DTAttributedTextView to display.

And no, I’m not referring to Amy spelling “center” incorrectly throughout. 🙂

The run delegate is missing.

If I paste this code into DemoAboutViewController, reducing the attachment display size to 100×100. This comes out quite weird.

Screen Shot 2013-04-07 at 2.38.20 PM

Apparently this spaces the lines correctly from the top (done in DTCoreTextLayoutFrame), but the ascender of the image (the part going up from the base line) is only as high as the font’s ascender. This explains why in Amy’s sample image the divider looks like it is vertically in the correct position. It has a height similar to the font height.

Let’s add in the missing run delegate.

// need run delegate for sizing
CTRunDelegateRef embeddedObjectRunDelegate = createEmbeddedObjectRunDelegate((id)attachment);
[newAttributes setObject:(__bridge id)embeddedObjectRunDelegate forKey:(id)kCTRunDelegateAttributeName];
CFRelease(embeddedObjectRunDelegate);

Build&Run and we can marvel at the correct placement of my face.

Screen Shot 2013-04-07 at 2.45.24 PM

Pretty, eh? (I mean the positioning)

To simplify things I have this category on NSAttributedString in DTRichTextEditor for inserting images into the editable text.

+ (NSAttributedString *)attributedStringWithImage:(UIImage *)image maxDisplaySize:(CGSize)maxDisplaySize
{
   DTTextAttachment *attachment = [[DTTextAttachment alloc] init];
   attachment.contents = (id)image;
   attachment.originalSize = image.size;
   attachment.contentType = DTTextAttachmentTypeImage;
 
   CGSize displaySize = image.size;
   if (!CGSizeEqualToSize(maxDisplaySize, CGSizeZero))
   {
      if (maxDisplaySize.width < image.size.width || 
          maxDisplaySize.height < image.size.height)
      {
         displaySize = sizeThatFitsKeepingAspectRatio(image.size,maxDisplaySize);
      }
   }
   attachment.displaySize = displaySize;
 
   DTHTMLElement *element = [[DTHTMLElement alloc] init];
   element.textAttachment = attachment;
 
   return [element attributedString];
}

This constructs the attributed string with the image exactly like DTCoreText does, via DTHTMLElement. There you can find that the run delegate is being added if the attachment property is not nil. This also adjusts the display size to fit a given maximum display size unless you pass CGSizeZero for that.

Conclusion

In DTCoreText (on iOS) besides a DTTextAttachment we need to also specify a run delegate so that Core Text is able to reserve the appropriate space for it. On Mac attributed strings can have attachments as well. There they are embedded in NSTextAttachment instances which have a file wrapper for the file as well as a cell for sizing and displaying the content.

Apple has brought over NSTextAttachment in iOS 6, but kept it private API. This is why I came up with this workaround using the killer combo of Run Delegate + DTTextAttachment. This is compatible all the way down to iOS 4.

]]>
https://www.cocoanetics.com/2013/04/dtcoretext-centering-an-image/feed/ 3 7991
Using Custom Fonts with DTCoreText https://www.cocoanetics.com/2013/03/using-custom-fonts-with-dtcoretext/ https://www.cocoanetics.com/2013/03/using-custom-fonts-with-dtcoretext/#respond Wed, 20 Mar 2013 14:36:48 +0000 http://www.cocoanetics.com/?p=7854 Friend of DTCoreText Holger was having problems getting DTCoreText to use the bold font face of his custom font.

I want to take this opportunity to explain what the root cause for Holger’s problem was and what you need to know if you’re using custom fonts with DTCoreText.

DTCoreText has access to all the fonts that are installed on the iOS device, as well as those that you bundle with your app. Fonts are always grouped by Font Family. The individual looks are called Font Faces. Typically you will have 4 variants there: regular, bold, italic and bold+italic.

Apple’s Core Text system supports TrueType (TTF) as well as OpenType (OTF) fonts.

Bundle the Font

After copying the font files into your app, you assigning them to the target so that they get copied together with the other app resources. You have to register the font file names in your app’s info.plist so that they get loaded on app launch.

The font files go into the “Fonts provided by application” section, aka UIAppFonts.

Add fonts to info.plist

To check if the fonts get loaded correctly you can simply create them by name, for example via this temporary code in your app delegate.

CTFontRef font = CTFontCreateWithName(CFSTR("CharterITC-Regu"), 20, NULL);
NSLog(@"%@", font);

If the font can be instantiated then the NSLog will output a description where you should see the same font name as in your creation statement.

CTFont <name: CharterITC-Regu, size: 20.000000, matrix: 0x0>
CTFontDescriptor <attributes: <CFBasicHash 0x7e24f60 [0x222fb48]>{type = mutable dict, count = 1,
entries =>
 1 : <CFString 0x14ddc40 [0x222fb48]>{contents = "NSFontNameAttribute"} = <CFString 0x7e24d90 [0x222fb48]>{contents = "CharterITC-Regu"}
}

Having verified that the font is available at run time you can now proceed to use it in text.

Using the Custom Font

When somebody says “I’m using this font” then he means “I am using the faces of this font family” because he expects that DTCoreText should select the appropriate font face based on whether or not regular or bold text is required.

The selection process works by CSS styles, <b>, <strong>, <em> and <i> tags modifying a HTML tag’s fontDescriptor. When the NSAttributedString is being assembled then this local fontDescriptor is called with newMatchingFont to produce a font (or get one from cache) that matches the description.

The modern way to specify a font for text in HTML is to apply a style:

Font via Style

The (outdated) alternative – which is also still supported – is to specify the font face directly via the <font> tag. There the attribute name for the font family is – misleadingly – called “face”.

Debugging Font Matching

In Holger’s problem everything was set up correctly as described above, but still bold and regular text would end up using the same regular font face. Problems like this can happen if the font files come from a dubious source that didn’t take good care to set the font meta information correctly.

There’s a simple check you can perform if you run into these kinds of problems with a custom font. Create a DTCoreTextFontDescriptor from the CTFont and output the CSS style representation. Or you just set a breakpoint after the creation of the descriptor and inspect its properties.

DTCoreTextFontDescriptor *newDesc = [[DTCoreTextFontDescriptor alloc] initWithCTFont:font];
NSLog(@"%@", [newDesc cssStyleRepresentation]);

In this example the output was:

font-family:'Charter ITC';font-size:20px;font-weight:bold;

So we see that even though we passed in the CharterITC-Regu from before this face appears to have a bold trait. This should not be and is a mistake.

If both the regular font face and the bold one have the bold font trait then Core Text prefers the regular one.

Workaround / Speed Improvement

Since font matching is a painfully slow process I implemented a global font override table in DTCoreText. This override table is seeded with the contents of DTCoreTextFontOverrides.plist which contains the basic setup suitable for most preinstalled fonts on iOS.

The override table specifies a combination of font family and bold and italic traits. When a bold face from a certain family is requested then DTCoreText can simple look up the font face name and create the CTFont from that. This is many times faster than doing a font search via Core Text.

This is why I recommend that you include this plist with your app’s resources, if only for the faster font lookup. Without it all still works, but if you have many alternating fonts then this unnecessarily slows down your app.

To get the same performance benefit for custom fonts you can simply add your custom font to the global override table. Incidentally this can also be used to work around fonts with incorrect traits. You should make these additions right after app launch, once a font has been matched it is cached and then this registration will be too late.

// these fix the bold problem
[DTCoreTextFontDescriptor setOverrideFontName:@"CharterITC-Bold" forFontFamily:@"Charter ITC" bold:YES italic:NO];
[DTCoreTextFontDescriptor setOverrideFontName:@"CharterITC-BoldItal" forFontFamily:@"Charter ITC" bold:YES italic:YES];
 
// these are for completeness to get the faster lookup
[DTCoreTextFontDescriptor setOverrideFontName:@"CharterITC-Regu" forFontFamily:@"Charter ITC" bold:NO italic:NO];
[DTCoreTextFontDescriptor setOverrideFontName:@"CharterITC-ReguItal" forFontFamily:@"Charter ITC" bold:NO italic:YES];

An alternative would be to add these 4 lines to the plist which you should be packaging with your app anyway. Though I slightly prefer the registration in code because if you use DTCoreText via CocoaPods you cannot modify the overrides plist file. But that’s your call.

Conclusion

When encountering font matching issues with external fonts you should first inspect the individual font faces if they possibly are having incorrectly specified traits. But in any case I recommend that you include the DTCoreText DemoApp’s font overrides plist with your app to speed up the matching. You can add your custom fonts in there or in code to have them included in the override process.

]]>
https://www.cocoanetics.com/2013/03/using-custom-fonts-with-dtcoretext/feed/ 0 7854
Today’s Hero: CHEN Xian’an https://www.cocoanetics.com/2013/03/todays-hero-chen-xianan/ https://www.cocoanetics.com/2013/03/todays-hero-chen-xianan/#respond Tue, 05 Mar 2013 18:17:33 +0000 http://www.cocoanetics.com/?p=7723 I was having a problem in DTCoreText where the multi-byte sequence making up an Emoji would not get properly encoded by DTHTMLWriter. A quick peeking into NSHTMLWriter didn’t bring relief either, Apple is not encoding these characters, but leaves them unencoded.

You can see in this screenshot that I looked at how NSHTMLWriter would encode two Emojis:

NSHTMLWriter Non-Encoding

That’s not the proper way for us, we want our output to be safe with any kind of transport encoding because it might end up on a machine that does not support UTF8 as brilliantly as iOS and OS X do.

My first idea was that I might have to force the font family to be “Apple Color Emoji” which is the font that CoreText falls back to for displaying Emojis. However if you don’t have the proper encoding even setting the font family does not help.

The problem was in NSString+HTML in DTCoreText which I use in DTHTMLWriter to add HTML entities. I created an issue on GitHub to describe my plight and while I was still dabbling around with libxml2 looking for an answer there Xian’an stepped in, fixed the bug and sent a pull request. Brilliant, simply brilliant!

The solution is to use some wide unicode supporting methods found in Core Foundation, more precisely CFString.

// ... looping through the unicars
if (oneChar<=255)
{
   [tmpString appendFormat:@"%C", oneChar];
}
else if (CFStringIsSurrogateHighCharacter(oneChar) && i < [self length]-1)
{
   i++;
   unichar surrogateLowChar = [self characterAtIndex:i];
   UTF32Char u32code = CFStringGetLongCharacterForSurrogatePair(oneChar, surrogateLowChar);
   [tmpString appendFormat:@"&#%lu;", (unsigned long)u32code];
}
else
{
   [tmpString appendFormat:@"&#%d;", oneChar];
}

CFStringIsSurrogateHighCharacter checks if the current unichar character is a "Surrogate High Character". If yes then CFStringGetLongCharacterForSurrogatePair retrieves the 32-bit wide character value.

It's late, I'm tired and annoyed from having to re-tag DTCoreText 1.3.2 three times, but I just had to write this up for the whole world to know ...

Thank you CHEN Xian'an, your mad bug fixing skillz my day!

]]>
https://www.cocoanetics.com/2013/03/todays-hero-chen-xianan/feed/ 0 7723
Zarra on Locking https://www.cocoanetics.com/2013/02/zarra-on-locking/ https://www.cocoanetics.com/2013/02/zarra-on-locking/#comments Mon, 18 Feb 2013 08:27:23 +0000 http://www.cocoanetics.com/?p=7626 In my previous article dealing with Multi-Context Core Data I introduced a 3-context scheme that Marcus Zarra hat shown us in a back room at the 2012 NSConference.

Several people inquired about Locking, take for example Wim Fikkert:

Thanks for the great article. However, like Tom, I was wondering if the main context will not be blocked whenever you perform a save to disk with the persistent store. I am using the last design pattern, and I keep running into my app locking up. I have done some more searching and came across this article. Perhaps you can comment?

I don’t pretend to come anywhere close to being the Core Data expert that Zarra is, so I went straight to the horses mouth and asked him.

Marcus Zarra kindly responded shedding some light on the matter, emphasis mine.

There is always a lot of confusion around locking. [Editor: DOH!]

Whenever you save to the disk, no matter what context you are in, single or multiple, you are going to “lock” the NSPersistentStore while the write is taking place. That has always been true and most likely always will be true.

What is not true is that the main context gets locked. That is a over-simplification of what happens. If, during a save, you attempt to fetch more data from disk then you will be blocked. That is the effect people are seeing and screaming about.

Aha, so locking only affects a persistent store (aka the sqlite file). This is the 3-level approach I was referring to:

Here we see that we only have writing access to the PSC (Persistent Store Coordinator) in the background writer context. In my Open Source DTDownloadCache I am doing the actual save to disk on a delayed timer that checks if there are changes and if there are any saves them.

So what about all those other copies of the data that is already in memory?

However, if you are working with data that is already in memory then you won’t be blocked.

Also, depending on what you are fetching and how your fetch is configured, you can do a fetch that doesn’t block because the data is already in disk. That is harder to accomplish though so I relegate it to a side point. I should note that the default for a NSFetchRequest is to hit disk no matter what (this is the staleness interval)

The core problem is the locking of the NSPersistentStore. Since that cannot be avoided it needs to be lessened. To do that you spread it out into smaller hits so that the main (or other) contexts have a chance to get in and retrieve data frequently enough that the user does not get the sensation of “locking”. Small/frequent saves during imports is a common solution.

Now reading access is something that might cause a pause when NSFetchedResultsController cannot find current data in the Main MOC. Then it has to inquire its parent context for the data which has to get it from disk.

And of course Zarra also has an alternative but he doubts the viability of that even himself:

Another solution that is a bit hairy is to have *two* NSPersistentStoreCoordinator instances, one for writing one for reading. However that gets very complex very fast and I never recommend it. With a double PSC design you must tell the primary context when things change because it has no automatic notification. I mention it for completeness of the answer as opposed to a suggestion. I have yet to see that solution end well 🙂

Let’s recap:

  • writing to disk = locking the store, always
  • accessing data already in memory does not lock inside the staleness interval, otherwise is has to go up the chain an eventually get fresh data from disk
  • importing data = small/frequent saves (decoupled as shown above)

My personal conclusion is that you’ll have to experiment with how frequent you call a save on the Managed Object Context that is connected to your persistent store. There might be scenarios where you can get away with saving all the time and other where you should wait for an opportune moment in UI interaction when the user wouldn’t notice a slight pause on the main thread.

Thank you Marcus Zarra for your generously dispensed insight!

]]>
https://www.cocoanetics.com/2013/02/zarra-on-locking/feed/ 15 7626