It's as though NSDictionaryOfVariableBindings is interpreting the literal text I'm passing rather than evaluating the statement
This is exactly what is happening. If you command-click on NSDictionaryOfVariableBindings
, you will see its definition as a macro that calls a private(ish) UIKit function in NSLayoutConstraint.h
:
#define NSDictionaryOfVariableBindings(...) _NSDictionaryOfVariableBindings(@"" # __VA_ARGS__, __VA_ARGS__, nil)
UIKIT_EXTERN NSDictionary *_NSDictionaryOfVariableBindings(NSString *commaSeparatedKeysString, id firstValue, ...) NS_AVAILABLE_IOS(6_0); // not for direct use
The @"" # __VA_ARGS__
in the macro definition turns the list of passed arguments into a literal string, which is passed as the commaSeparatedKeysString
parameter to the _NSDictionaryOfVariableBindings
function.
The correct way to use NSDictionaryOfVariableBindings
is to use locally-scoped variables, or _
-prefixed ivars if applicable. If you don’t want to do that, you can always make your own dictionary, using whatever literal string you want for the key and whatever value you want as the value. I often do this to rename my variables to something meaningful for the visual format language string. So, in your example:
UILabel *label = [[UILabel alloc] init];
NSMutableDictionary *items = [[NSMutableDictionary alloc] init];
[items setValue:label forKey:@"label"];
[NSLayoutConstraint constraintsWithVisualFormat:@"|-[label]-|"
options:0
metrics:nil
// using Obj-C dictionary subscripting syntax
views:@{ @"label" : items[@"label"] }];
Your example may be contrived, but in case it is not, the fact that UILabel *label
is in scope means you could just pass NSDictionaryOfVariableBindings(label)
for the views:
parameter.
Edit: your items
mutable dictionary is already correctly set up to just pass in as the views:
parameter, if you want.