3 ms·
Some of that document is out of date - Interface Builder does have support for Auto Layout now. Auto Layout also has a space now. ;-) I like to spell it [Auto
by kenferry 15y ago
Some of that document is out of date - Interface Builder does have support for Auto Layout now. Auto Layout also has a space now. ;-) I like to spell it [Auto]-[Layout] (see the ASCII art programming language part of that document).
People may also be interested in the WWDC session on Auto Layout: http://goo.gl/5sSgK http://goo.gl/5sSgK (requires free developer account).
Some interesting aspects of the system to me:
(1) The use of fairly simple but freeform constraints. The numerical solver is based on work in this paper, http://goo.gl/6fHdd http://goo.gl/6fHdd. They end up covering really a lot of stuff you want to do in a natural way, and with a single constraint object with few properties.
(2) The emphasis on visualization. Most of the time constraints are created visually, in Interface Builder, by dragging objects around and snapping them together. When doing layout in source code, you use an ASCII art inspired format string that visually looks like the interface you're trying to create. When debugging at runtime, you can ask a window to draw constraints on screen, so that you can see what they are. (The debugging support itself is also interesting.)
(3) The reworking of how layout fits into Cocoa's model-view-controller design. Previously, too much was in the controller layer - to do layout you ended up having to say things that you didn't really know, because it was data intrinsically known by the view layer. By reworking the layering, the views can take responsibility for those aspects of layout that are intrinsically known to the view. This takes a lot of pressure off, because (a) you don't have to specify things you don't know, (b) there's less work to do because the views are doing some of it, (c) a lot of the time the views are coming out of AppKit, so you never have to write the view parts at all. It also aligns the easiest thing to do (don't mess with the views) with the right thing to do (use standard OS behavior). If you want to make it do something unusual, you can, but you have to say so. Your code records the places you intentionally deviated.
[Disclosure - I worked on this.]
- dirtyaura 15y ago> When doing layout in source code, you use an ASCII art inspired format string that visually looks like the interface you're trying to create. This is a cool idea. Instead of specifying layout inside strings, did you consider syntactic sugar or macros to do it in code?
- kenferry 15y agoYes… let's talk macros first. Actually, first first you should look at multi-dimensional analog literals if you haven't seen it, http://weegen.home.xs4all.nl/eelis/analogliterals.xhtml http://weegen.home.xs4all.nl/eelis/analogliterals.xhtml. Awesome/yikes. Okay, back. What are the reasons to consider macros? Probably, compile time checking and ability to directly use variables that are in scope (e.g., fooButton for some button). The goal of compile time checking is really debugging, to make it easy to find and fix mistakes. Now, in a format string, we don't have compile time checking, but we can have really good, descriptive error messages. Our diagnostics were inspired by those in clang, http://blog.llvm.org/2010/04/amazing-feats-of-clang-error-recovery.html http://blog.llvm.org/2010/04/amazing-feats-of-clang-error-re..., right down to the carat pointing at the problem within the code. Maybe we could have done that with macros? I guess I didn't really try that hard, but usually if you mess up a macro, you're going to get something really cryptic from the compiler. Also, it's wayyyy easier for the client to grok and feel comfortable with a format string than with a crazy macro system. You know how we're parsing the string. You could implement it yourself if you had to. It's understandable, and you can see that there won't be side effects. Now consider that multi-dimensional analog literals link above. Does it work? Heck yeah! Do you want black magic like that in your code, with behavior you don't understand (at least without way more investment in understanding than we want to require)? Probably not! Plus, we're likely to have to compromise on the visual design of the language now and/or in the future to contort it into what's technically possible in macros over ObjC. This will also hurt debugging, in that you'll be less likely to quickly understand what your code says. So for debugging, I don't think macros are actually going to be a win, despite the compile time checking. And really, the above concerns are enough to kill macros for me. Plus, we might be able to recover most of the compile time checking anyway. I'd love to see clang's __attribute__ format extended to do checking of Cocoa visual format strings. http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html#index-Wformat-2426 http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html#i.... We have a bug tracking this. Ability to directly use variables is a positive for macros. As is, we have to pass a dictionary on the side that maps identifiers to actual view objects. In python you could pass locals(), but ObjC doesn't maintain a symbol table at runtime. For this we actually do pull a skankier-than-usual macro trick to make things easier. id views = NSDictionaryOfVariableBindings(fooButton, barButton); expands to something equivalent to id views = _NSDictionaryOfVariableBindings(@"fooButton, barButton", fooButton, barButton, nil); and _NSDictionaryOfVariableBindings parses the comma separated string to make a dictionary mapping @"fooButton" -> fooButton. #define NSDictionaryOfVariableBindings(...) _NSDictionaryOfVariableBindings(@"" # __VA_ARGS__, __VA_ARGS__, nil) APPKIT_EXTERN NSDictionary *_NSDictionaryOfVariableBindings(NSString *commaSeparatedKeysString, id firstValue, ...); // not for direct use Okay, last, why not make this an actual part of Objective-C, like regexes are in some languages or like LINQ is in C#. I feel like the reasoning here is more wishy-washy, so I don't know, maybe it's wrong and we'll revisit it. Our system has a continuum from leaf code on which nothing else depends, like apps, down through AppKit, Foundation, and Objective-C. The continuum isn't really defined by what framework some code is in, it's defined by how much sits on top of it in the dependency stack. As you go down toward the deeper and more built-upon parts of the system, reliability becomes more and more important, and our ability to cheaply change our minds if an interface isn't working out goes down. The standards for simplicity and wide applicability go up and up. Objective-C's deep. You can literally learn _all_ of Obj-C in a weekend if you know C. We like that. In recent releases we have relayered things like memory management (GC, ARC) and properties from being framework conventions to being formal parts of the language. But that's where the language is right now. There's a pretty clear divide between language and framework, and the language doesn't reach up and violate the layering much. If we're thinking about moving something like these layout format strings into the language, we should also be thinking about printf-style format strings (or other templating), Core Data predicates, regular expressions and lots of other Cocoa-ness - basically obliterating the existence of any kind of layer boundary between ObjC and Cocoa. These would be extremely controversial changes, inside and outside of Apple. That doesn't necessarily make them wrong, but I'm not confident they're right. Anyway, it's something that could be considered in the future.
- babel17 15y agoI wonder about the NSDictionaryOfVariableBindings used in the example. Never have seen that before, very interesting.
- kenferry 15y agoIt's also new with this API.
- babel17 15y agoI wonder how this constraint approach fits together with classic design principles. For example, an often used design principle is that of grid systems. Does the constraint approach somehow naturally include the grid systems approach?