Impossible d'utiliser une classe Swift depuis un context JavaScriptCore...

ilbouedilboued Membre
juillet 2015 modifié dans Objective-C, Swift, C, C++ #1

J'essaye désespérément d'utiliser une classe créée en Swift depuis un context JavaScriptCore... et je tourne en rond :-(


 


J'utilise un Playground, OSX 10.10.4 et Xcode 6.4 (j'ai aussi fait des essais avec Xcode 7 beta 3 sans plus de succès). 


 


Voici mon code :



//: Playground - noun: a place where people can play
import Foundation
import JavaScriptCore

let context = JSContext()

// errors handling
context.exceptionHandler = { context, exception in
println("JS Error: \(exception)")
}



@objc protocol PersonJavaScritMethod : JSExport {
    func sayHello()
    static func create(name : String) -> Person
}

class Person : NSObject, PersonJavaScritMethod {
    var name : String!

    init(name:String) {
super.init()
println("# init done #")
self.name = name
}

class func create(name : String) -> Person {
return Person(name: name)
}

func sayHello() {
println("Hello \(name)")
}
}

let aPerson = Person.create("Toto")
// -> ok : console output : "# init done #"
aPerson.sayHello()
// -> ok : console output : "Hello Toto"

context.globalObject.setObject(Person.self, forKeyedSubscript: "Person")
context.evaluateScript("Person.create('Mike')")
// -> not ok : console output :
// "JS Error: TypeError: undefined is not a function (evaluating 'Person.create('Mike')')"

Réponses

  • Curieusement... après avoir tourné en rond comme un couillon, j'ai fini par trouver que cela fonctionne bien si :


    - Ce code est dans une application ligne de commande


    ou


    - Si le code de la classe et du protocole associé sont dans un fichier mis dans le répertoire Sources du Playground, avec les mentions 'public' ad'hoc... sur la classe et les fonctions que l'on veut rendre publiques depuis le Playground :-)


     


    ==> C'est un problème spécifique au Playground... je ne vois ceci dit pas pourquoi cela ne fonctionne pas tel que... (cad sans mettre à  part le protocole et la classe associée)


  • Joanna CarterJoanna Carter Membre, Modérateur
    juillet 2015 modifié #3
    Par défaut, la visibilité des classes et de ses membres est internal, voir visible seulement de l'intérieur du module où la classe est déclarée.


    Du coup, le code JavaScriptCore, étant dans un module à  l'exterieur de ton module, ne peut pas voir ta classe et ses fonctions que si tu les mettes en visibilité public.
  • @Joanna Carter, je comprends bien ton raisonnement qui me semble logique... mais ce n'est pas ce que je constate en pratique  :


     


    - en mettant ce code sans modification (cad SANS les mots clefs public) dans un même fichier main.swift d'une application console -> OK


     


    - le même code dans un Playground (AVEC ou SANS les public ad'hoc) -> pas OK


     


    - ce code dans un Playground en deux morceaux, en mettant la classe et le protocole associés dans un fichier du répertoire ressource, et AVEC les public ad'hoc -> OK


     


    Il doit y avoir une autre logique :-/

  • AliGatorAliGator Membre, Modérateur
    Cette différence de fonctionnement ne me choque pas, surtout vu le contexte d'utilisation

    Effectivement, le code exécuté dans le contenu d'un Playgound est du top-level-code qui peut avoir un comportement un peu différent de quand ton code est compilé. Dans 90% des cas le comportement est le même, mais dans un Playground ça reste du contenu exécuté un peu comme un "script", et à  l'extérieur d'un contexte de module.

    Un peu de lecture sur le blog officiel à  ce sujet.

    Le code que tu tapes dans le playground, il est réévalué et exécuté à  chaque fois que tu le modifies ou relance le playground, c'est un peu du "live". Le code que tu mets dans Sources par contre, il est compilé une fois pour toutes, dans un module automatiquement importé quand le code du Playground est évalué.

    Et avec JSContext c'est à  mon avis encore un peu particulier, puisque tu bridges avec un environnement qui a un peu son propre Runtime, une machine virtuelle pour Javascript... je me demande s'il ne faut pas absolument avoir une RunLoop par exemple, ce que tu n'as pas dans un contexte de Playground ? Et dans tous les cas ça ne paraà®t pas déconnant que pour que JSContext puisse voir ta classe il faut qu'elle soit compilée dans un module (et public, bien sûr)
  • @AliGator : ce qui est curieux, c'est que cela marche très bien :


     


    - dans une application type console... qui ne contient pas de runLoop, juste un fichier main.swift.


     


    - dans un fichier unique executable dans la console du type swift.command (tel qu'évoqué dans le lien du blog officiel que tu indiques, avec le prefix ad'hoc (#!/usr/bin/xcrun swift)


     


    Mais bon, ce qui est certain, c'est que l'environnement d'execution du Playground n'est pas classique et au fond cette limitation n'est pas vraiment gênante... même si j'aurais bien aimé comprendre la raison exacte de ce comportement histoire d'anticiper ce qui pourrait ne pas fonctionner dans un playground... et m'éviter d'y passer du temps en pensant que si mon code ne marchait pas bien dans mon playground... c'était parce que j'utilisais mal JavaScriptCore.


     


    Merci en tout cas pour vos éclairages :-)


Connectez-vous ou Inscrivez-vous pour répondre.