2017-04-21 1 views
0

Dans CMIconManager.m J'ai une fonction appelée getImageForIcon.React Native Bridge - exporter une fonction dans un autre fichier dans Objective-C

- (UIImage *)getImageForIcon:(CMIcon)icon fontSize:(CGFloat)fontSize fontColor:(UIColor *)fontColor imageWidth:(CGFloat)imageWidth imageHeight:(CGFloat)imageHeight backgroundCircleColor:(UIColor *)backgroundCircleColor backgroundCircleSize:(CGFloat)backgroundCircleSize { 
    // set up the squares we will be drawing in... 
    CGSize imageSize = CGSizeMake(imageWidth, imageHeight); 
    CGRect imageRect = CGRectMake(0, 0, imageSize.width, imageSize.height); 
    CGSize circleSize = CGSizeMake(backgroundCircleSize, backgroundCircleSize); 
    CGRect circleRect = CGRectMake((imageWidth - backgroundCircleSize)/2, (imageHeight - backgroundCircleSize)/2, circleSize.width, circleSize.height); 

    // start the drawing context... 
    UIGraphicsBeginImageContextWithOptions(imageSize, NO, [[UIScreen mainScreen] scale]); 
    CGContextRef ctx = UIGraphicsGetCurrentContext(); 

    // fill the image background with transparent alpha... 
    CGContextScaleCTM(ctx, 1, -1); 
    CGContextTranslateCTM(ctx, 0, -imageRect.size.height); 
    CGContextSetAlpha(ctx, 0.0); 
    CGContextFillRect(ctx, CGRectMake(0, 0, imageSize.width, imageSize.height)); 

    // reset subsequent drawing to non-transparent... 
    CGContextSetAlpha(ctx, 1.0); 

    // fill in a solid background circle, centered, if needed... 
    if (![backgroundCircleColor isEqual:[UIColor clearColor]] || !backgroundCircleColor) { 
    CGContextSetLineWidth(ctx, 1.0); 
    CGContextSetFillColorWithColor(ctx, backgroundCircleColor.CGColor); 
    CGContextFillEllipseInRect(ctx, circleRect); 
    } 

    // draw the icon, centered in the image... 
    if ([fontColor isEqual:[UIColor clearColor]]) { 
    CGContextSetBlendMode(ctx, kCGBlendModeClear); 
    } 
    NSAttributedString *theString = [self attributedStringForIcon:icon fontSize:fontSize color:fontColor]; 
    if (theString.length >= 1) { 
    CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef) (theString)); 
    CGFloat widthConstraint = imageWidth; 
    CGSize suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints(frameSetter, CFRangeMake(0, theString.length), NULL, CGSizeMake(widthConstraint, CGFLOAT_MAX), NULL); 
    CGFloat distanceFromTop = (imageWidth - suggestedSize.height)/2; 
    CGFloat distanceFromLeft = (imageHeight - suggestedSize.width)/2; 
    CGMutablePathRef path = CGPathCreateMutable(); 
    CGPathAddRect(path, NULL, CGRectMake(distanceFromLeft, distanceFromTop, suggestedSize.width, suggestedSize.height)); 
    CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, NULL); 
    CTFrameDraw(frame, ctx); 
    CFRelease(frame); 
    CFRelease(path); 
    CFRelease(frameSetter); 
    } 

    // save the current context in a UIImage object... 
    UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    return finalImage; 
} 

Comment passer dois-je cette fonction à RCT_EXPORT_METHOD() dans le nouveau fichier: RNIconManager.m?

#import "RNIconManager.h" 
#import "CMIconManager.h" 

@implementation RNIconManager 
RCT_EXPORT_MODULE(); 

CMIconManager *getIcons = [[CMIconManager alloc] init]; 

RCT_EXPORT_METHOD(getImageForIcon:(UIImage*)icon 
        fontSize:(CGFloat)fontSize 
        fontColor:(UIColor *)fontColor 
        imageWidth:(CGFloat)imageWidth 
        imageHeight:(CGFloat)imageHeight 
        backgroundCircleColor:(UIColor *)backgroundCircleColor 
        backgroundCircleSize:(CGFloat)backgroundCircleSize 
        callback:(RCTResponseSenderBlock) callback) 
{ 
    callback(@[getIcons(icon, fontSize, fontColor,imageWidth, imageHeight, backgroundCircleColor, backgroundCircleSize)]); 
} 
+0

Il me semble que 'getImageForIcon' est méthode d'instance, mais vous utilisez cette classe comme méthode. – Ryan

+0

C'est très possible. Je suis complètement nouveau à Objective C et je peux l'utiliser plus comme JavaScript. Quelle serait la différence en Objective C? – Turnipdabeets

+0

Modifiez '- (UIImage *)' en '+ (UIImage *)', mais il n'existe aucun moyen efficace d'envoyer des données de la méthode class à une instance. J'ai utilisé 'NSNotificatio' à la place. – Ryan

Répondre

0

La RCT_EXPORT_METHOD macro prend toute signature de la méthode en tant que paramètre, il ressemblerait à quelque chose comme ceci:

RCT_EXPORT_METHOD(getImageForIcon:(UIImage*)icon 
        fontSize:(CGFloat)fontSize 
        fontColor:(UIColor *)fontColor 
        imageWidth:(CGFloat)imageWidth 
        imageHeight:(CGFloat)imageHeight 
        backgroundCircleColor:(UIColor *)backgroundCircleColor 
        backgroundCircleSize:(CGFloat)backgroundCircleSize) 
{ 
    //your function content goes here 
} 

Quelques notes:

  1. Vous pouvez » N'utilisez aucun type dans vos méthodes. Vous ne pouvez utiliser que des types que RN sait convertir, vous ne pouvez donc pas utiliser CMIcon.
  2. Vous ne pouvez pas simplement renvoyer des valeurs à partir de méthodes exportées. Si vous devez retourner quelque chose, vous devrez passer un rappel ou utiliser des promesses.
  3. Si la fonction réelle que vous souhaitez appeler se trouve dans une autre classe, vous devrez toujours effectuer l'exportation, mais dans cette méthode exportée, vous pouvez appeler une autre méthode - il peut s'agir d'une méthode statique ou d'une instance méthode selon comment votre code est écrit.

Vous devriez vraiment consulter la documentation pour Native Modules, il a toutes les informations et les exemples dont vous avez besoin.

Edit: Voici un exemple de la façon dont vous pouvez exposer une méthode de classe que vous pouvez appeler statiquement:

//in your h file 
@interface CMIconManager : NSObject 
+ (UIImage*)getImageForIcon:(UIImage*)icon fontSize:(CGFloat)fontSize fontColor:(UIColor *)fontColor imageWidth:(CGFloat)imageWidth imageHeight:(CGFloat)imageHeight backgroundCircleColor:(UIColor *)backgroundCircleColor backgroundCircleSize:(CGFloat)backgroundCircleSize callback:(RCTResponseSenderBlock) callback; 
@end 

//in your m file 
@implementation CMIconManager 
+ (void)getImageForIcon:(UIImage*)icon fontSize:(CGFloat)fontSize fontColor:(UIColor *)fontColor imageWidth:(CGFloat)imageWidth imageHeight:(CGFloat)imageHeight backgroundCircleColor:(UIColor *)backgroundCircleColor backgroundCircleSize:(CGFloat)backgroundCircleSize callback:(RCTResponseSenderBlock) callback 
{ 
    //your implementation 
} 
@end 

//call the method 
[CMIconManager getImageForIcon:icon fontSize:size fontColor:color imageWidth:width imageHeight:height backgroundCircleColor:backgroundColor backgroundCircleSize:circleSize callback:callback]; 
+0

Merci @Artal, j'ai lu la documentation sur les modules natifs mais je manque de compréhension de l'objectif C. Cependant, je comprends les deux premiers points que vous avez faits ici. J'ai donc fait des changements dans mon code. La fonction listée ci-dessus est une fonction trouvée dans une autre classe que je souhaite réutiliser et appeler à l'extrémité JS. Comment puis-je appeler cette méthode dans cette nouvelle classe à l'intérieur du rappel? Avec le code mis à jour, je vois des erreurs "Type d'objet appelé 'CMIconManager *' n'est pas une fonction ou un pointeur de fonction." et "l'élément Initializer n'est pas une constante de compilation". – Turnipdabeets

+0

Vous ne pouvez pas créer une instance d'un objet flottant dans votre code, c'est pourquoi vous obtenez l'erreur 'L'élément Initializer n'est pas une constante de compilation '. En outre, vous essayez d'utiliser cette instance comme un appel à une méthode et même ainsi - ce n'est pas la syntaxe pour appeler des méthodes d'instance dans Objective C. Vous devrez soit mettre votre code dans le 'RCT_EXPORT_METHOD', ou vous peut transformer 'getImageForIcon' en méthode de classe pour que vous puissiez l'appeler statiquement. – Artal

+0

@Turnipdabeets J'ai édité ma réponse pour fournir un exemple de la façon dont vous pouvez appeler votre méthode statiquement. Vous devriez savoir cependant que vous allez rencontrer des problèmes supplémentaires car il n'est pas possible de passer un objet 'UIImage' sur le pont, seuls les types sérialisables sont autorisés.Vous devrez l'enregistrer dans un fichier et fournir une URL, ou vous pouvez regarder comment les autres classes RN le font en interne, je pense qu'ils ont une sorte de classe d'assistance pour le gérer. – Artal