re-work the doctor command
diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart
index 33af902..d005f32 100644
--- a/packages/flutter_tools/lib/src/ios/devices.dart
+++ b/packages/flutter_tools/lib/src/ios/devices.dart
@@ -79,7 +79,7 @@
   bool get supportsStartPaused => false;
 
   static List<IOSDevice> getAttachedDevices([IOSDevice mockIOS]) {
-    if (!doctor.iosWorkflow.hasIdeviceId)
+    if (!doctor.iosWorkflow.hasIDeviceId)
       return <IOSDevice>[];
 
     List<IOSDevice> devices = [];
diff --git a/packages/flutter_tools/lib/src/ios/ios_workflow.dart b/packages/flutter_tools/lib/src/ios/ios_workflow.dart
index 10b1447..8df90c7 100644
--- a/packages/flutter_tools/lib/src/ios/ios_workflow.dart
+++ b/packages/flutter_tools/lib/src/ios/ios_workflow.dart
@@ -8,112 +8,96 @@
 import '../doctor.dart';
 import 'mac.dart';
 
-class IOSWorkflow extends Workflow {
-  @override
-  String get label => 'iOS toolchain';
+XCode get xcode => XCode.instance;
+
+class IOSWorkflow extends DoctorValidator implements Workflow {
+  IOSWorkflow() : super('iOS toolchain - develop for iOS devices');
 
   @override
   bool get appliesToHostPlatform => Platform.isMacOS;
 
   // We need xcode (+simctl) to list simulator devices, and idevice_id to list real devices.
   @override
-  bool get canListDevices => XCode.instance.isInstalledAndMeetsVersionCheck;
+  bool get canListDevices => xcode.isInstalledAndMeetsVersionCheck;
 
   // We need xcode to launch simulator devices, and ideviceinstaller and ios-deploy
   // for real devices.
   @override
-  bool get canLaunchDevices => XCode.instance.isInstalledAndMeetsVersionCheck;
+  bool get canLaunchDevices => xcode.isInstalledAndMeetsVersionCheck;
+
+  bool get hasIDeviceId => exitsHappy(<String>['idevice_id', '-h']);
 
   @override
   ValidationResult validate() {
-    Validator iosValidator = new Validator(
-      label,
-      description: 'develop for iOS devices'
+    List<ValidationMessage> messages = <ValidationMessage>[];
+    int installCount = 0;
+    String xcodeVersionInfo;
+
+    if (xcode.isInstalled) {
+      installCount++;
+
+      xcodeVersionInfo = xcode.xcodeVersionText;
+      if (xcodeVersionInfo.contains(','))
+        xcodeVersionInfo = xcodeVersionInfo.substring(0, xcodeVersionInfo.indexOf(','));
+
+      messages.add(new ValidationMessage(xcode.xcodeVersionText));
+
+      if (!xcode.isInstalledAndMeetsVersionCheck) {
+        messages.add(new ValidationMessage.error(
+          'Flutter requires a minimum XCode version of $kXcodeRequiredVersionMajor.$kXcodeRequiredVersionMinor.0.\n'
+          'Download the latest version or update via the Mac App Store.'
+        ));
+      }
+
+      if (!xcode.eulaSigned) {
+        messages.add(new ValidationMessage.error(
+          'XCode end user license agreement not signed; open XCode or run the command \'sudo xcodebuild -license\'.'
+        ));
+      }
+    } else {
+      messages.add(new ValidationMessage.error(
+        'XCode not installed; this is necessary for iOS development.\n'
+        'Download at https://developer.apple.com/xcode/download/.'
+      ));
+    }
+
+    // brew installed
+    if (exitsHappy(<String>['brew', '-v'])) {
+      installCount++;
+
+      List<String> installed = <String>[];
+
+      if (!exitsHappy(<String>['ideviceinstaller', '-h'])) {
+        messages.add(new ValidationMessage.error(
+          'ideviceinstaller not available; this is used to discover connected iOS devices.\n'
+          'Install via \'brew install ideviceinstaller\'.'
+        ));
+      } else {
+        installed.add('ideviceinstaller');
+      }
+
+      if (!hasIDeviceId) {
+        messages.add(new ValidationMessage.error(
+          'ios-deploy not available; this is used to deploy to connected iOS devices.\n'
+          'Install via \'brew install ios-deploy\'.'
+        ));
+      } else {
+        installed.add('ios-deploy');
+      }
+
+      if (installed.isNotEmpty)
+          messages.add(new ValidationMessage(installed.join(', ') + ' installed'));
+    } else {
+      messages.add(new ValidationMessage.error(
+        'Brew not installed; use this to install tools for iOS device development.\n'
+        'Download brew at http://brew.sh/.'
+      ));
+    }
+
+    return new ValidationResult(
+      installCount == 2 ? ValidationType.installed : installCount == 1 ? ValidationType.partial : ValidationType.missing,
+      messages,
+      statusInfo: xcodeVersionInfo
     );
-
-    ValidationType xcodeExists() {
-      return XCode.instance.isInstalled ? ValidationType.installed : ValidationType.missing;
-    };
-
-    ValidationType xcodeVersionSatisfactory() {
-      return XCode.instance.isInstalledAndMeetsVersionCheck ? ValidationType.installed : ValidationType.missing;
-    };
-
-    ValidationType xcodeEulaSigned() {
-      return XCode.instance.eulaSigned ? ValidationType.installed : ValidationType.missing;
-    };
-
-    ValidationType brewExists() {
-      return exitsHappy(<String>['brew', '-v'])
-        ? ValidationType.installed : ValidationType.missing;
-    };
-
-    ValidationType ideviceinstallerExists() {
-      return exitsHappy(<String>['ideviceinstaller', '-h'])
-        ? ValidationType.installed : ValidationType.missing;
-    };
-
-    ValidationType iosdeployExists() {
-      return hasIdeviceId ? ValidationType.installed : ValidationType.missing;
-    };
-
-    Validator xcodeValidator = new Validator(
-      'XCode',
-      description: 'enable development for iOS devices',
-      resolution: 'Download at https://developer.apple.com/xcode/download/',
-      validatorFunction: xcodeExists
-    );
-
-    iosValidator.addValidator(xcodeValidator);
-
-    xcodeValidator.addValidator(new Validator(
-      'version',
-      description: 'Xcode minimum version of $kXcodeRequiredVersionMajor.$kXcodeRequiredVersionMinor.0',
-      resolution: 'Download the latest version or update via the Mac App Store',
-      validatorFunction: xcodeVersionSatisfactory
-    ));
-
-    xcodeValidator.addValidator(new Validator(
-      'EULA',
-      description: 'XCode end user license agreement',
-      resolution: "Open XCode or run the command 'sudo xcodebuild -license'",
-      validatorFunction: xcodeEulaSigned
-    ));
-
-    Validator brewValidator = new Validator(
-      'brew',
-      description: 'install additional development packages',
-      resolution: 'Download at http://brew.sh/',
-      validatorFunction: brewExists
-    );
-
-    iosValidator.addValidator(brewValidator);
-
-    brewValidator.addValidator(new Validator(
-      'ideviceinstaller',
-      description: 'discover connected iOS devices',
-      resolution: "Install via 'brew install ideviceinstaller'",
-      validatorFunction: ideviceinstallerExists
-    ));
-
-    brewValidator.addValidator(new Validator(
-      'ios-deploy',
-      description: 'deploy to connected iOS devices',
-      resolution: "Install via 'brew install ios-deploy'",
-      validatorFunction: iosdeployExists
-    ));
-
-    return iosValidator.validate();
-  }
-
-  @override
-  void diagnose() => validate().print();
-
-  bool get hasIdeviceId => exitsHappy(<String>['idevice_id', '-h']);
-
-  /// Return whether the tooling to list and deploy to real iOS devices (not the
-  /// simulator) is installed on the user's machine.
-  bool get canWorkWithIOSDevices {
-    return exitsHappy(<String>['ideviceinstaller', '-h']) && hasIdeviceId;
   }
 }
diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart
index cd72155..388cc12 100644
--- a/packages/flutter_tools/lib/src/ios/mac.dart
+++ b/packages/flutter_tools/lib/src/ios/mac.dart
@@ -54,27 +54,24 @@
     }
   }
 
-  bool _xcodeVersionSatisfactory;
+  String _xcodeVersionText;
+
+  String get xcodeVersionText {
+    if (_xcodeVersionText == null)
+      _xcodeVersionText = runSync(<String>['xcodebuild', '-version']).replaceAll('\n', ', ');
+    return _xcodeVersionText;
+  }
+
   bool get xcodeVersionSatisfactory {
-    if (_xcodeVersionSatisfactory != null)
-      return _xcodeVersionSatisfactory;
+    RegExp regex = new RegExp(r'Xcode ([0-9.]+)');
 
-    try {
-      String output = runSync(<String>['xcodebuild', '-version']);
-      RegExp regex = new RegExp(r'Xcode ([0-9.]+)');
+    String version = regex.firstMatch(xcodeVersionText).group(1);
+    List<String> components = version.split('.');
 
-      String version = regex.firstMatch(output).group(1);
-      List<String> components = version.split('.');
+    int major = int.parse(components[0]);
+    int minor = components.length == 1 ? 0 : int.parse(components[1]);
 
-      int major = int.parse(components[0]);
-      int minor = components.length == 1 ? 0 : int.parse(components[1]);
-
-      _xcodeVersionSatisfactory = _xcodeVersionCheckValid(major, minor);
-    } catch (error) {
-      _xcodeVersionSatisfactory = false;
-    }
-
-    return _xcodeVersionSatisfactory;
+    return _xcodeVersionCheckValid(major, minor);
   }
 }