Desenvolvendo um plugin para o Xcode

Desenvolvendo um plugin para o Xcode

Palestra apresentada no 19º CocoaHeads São Paulo (01/03/2016).

Como você deve saber, o Xcode não é exatamente mil maravilhas. Entretanto, existe uma forma de adicionar ou alterar funcionalidades: plugins. Será mostrado as motivações para se criar um plugin, assim como os passos necessários.

841a0284060fa6faa652e95a467dcc69?s=128

Marcelo Fabri

March 01, 2016
Tweet

Transcript

  1. DESENVOLVENDO UM PLUGIN PARA O XCODE @MARCELOFABRI_

  2. None
  3. O PROBLEMA

  4. @property (weak, nonatomic) IBOutlet UILabel *textLabel;

  5. (weak, nonatomic)

  6. None
  7. The order of the attributes must be (nonatomic/atomic), (weak/strong/copy), (readonly),

    (nonnull/ null). — Nosso style guide
  8. None
  9. None
  10. None
  11. None
  12. XCODE EXPLORER

  13. BOILERPLATE @implementation IBOutlint + (instancetype)sharedPlugin { return sharedPlugin; } -

    (id)initWithBundle:(NSBundle *)plugin { if (self = [super init]) { // reference to plugin's bundle, for resource access self.bundle = plugin; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didApplicationFinishLaunchingNotification:) name:NSApplicationDidFinishLaunchingNotification object:nil]; } return self; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; }
  14. - (void)didApplicationFinishLaunchingNotification:(NSNotification*)noti { NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center removeObserver:self

    name:NSApplicationDidFinishLaunchingNotification object:nil]; [center addObserver:self selector:@selector(editorDocumentChanged:) name:@"IDEEditorDocumentDidChangeNotification" object:nil]; }
  15. - (void)editorDocumentChanged:(NSNotification *)notification { NSArray *array = notification.userInfo[@"IDEEditorDocumentChangeLocationsKey"]; id firstChange

    = array.firstObject; NSURL *url = [firstChange valueForKey:@"documentURL"]; if ([url isKindOfClass:[NSNull class]]) { return; } NSRange range = [[firstChange valueForKey:@"characterRange"] rangeValue]; // Check if it's a valid range if (range.length == 0 || range.location == NSNotFound) { return; }
  16. // Check if it's an IDESourceCodeDocument if (![notification.object respondsToSelector:@selector(textStorage)]) {

    return; } id textStorage = [notification.object textStorage]; NSAttributedString *attributed; @try { attributed = [textStorage attributedSubstringFromRange:range]; } @catch (NSException *exception) { return; }
  17. NSString *substring = attributed.string; NSDictionary *mapping = @{ @"@property (weak,

    nonatomic) IBOutlet " : @"@property (nonatomic, weak) IBOutlet ", @"@property (strong, nonatomic) IBOutlet " : @"@property (nonatomic, strong) IBOutlet " };
  18. [mapping enumerateKeysAndObjectsUsingBlock:^(NSString *prefix, NSString *replacement, BOOL * _Nonnull stop) {

    if ([substring hasPrefix:prefix]) { NSString *updatedSubstring = [substring stringByReplacingOccurrencesOfString:prefix withString:replacement]; [textStorage beginEditing]; [textStorage replaceCharactersInRange:range withString:updatedSubstring withUndoManager:nil]; [textStorage endEditing]; } }];
  19. replaceCharactersInRange:withString:withUndoManager: PRIVADO

  20. None
  21. @interface DVTTextStorage : NSTextStorage - (void)replaceCharactersInRange:(struct _NSRange)arg1 withString:(id)arg2 withUndoManager:(id)arg3; @end

  22. ✅ Notificações não documentadas ✅ Classes privadas ✅ @try/@catch "

    Method swizzling
  23. None
  24. GITHUB.COM/MARCELOFABRI/IBOUTLINT

  25. INCLUINDO NO ALCATRAZ { "name": "IBOutlint", "url": "https://github.com/marcelofabri/IBOutlint", "description": "Xcode

    plugin to change the order of the attributes when creating an IBOutlet in Xcode", "screenshot": "https://raw.githubusercontent.com/marcelofabri/IBOutlint/master/IBOutlint.gif" }
  26. !

  27. CONSELHOS > Sempre que puder, evite method swizzling > Muitos

    plugins são open source, dê uma olhada neles > Xcode-RuntimeHeaders > Se algum plugin não funcionar, pode ser por causa do UUID do Xcode
  28. ME@MARCELOFABRI.COM @MARCELOFABRI_