• Billet écrit dans : Mobile, iPhone 09.07.2009 10 Réactions !!

    Yop all,

    A la demande général de Fabrice Bernhard, voici une classe que j’ai faite pour me simplifier la vie quand je dois faire une requête HTTP. Vous me direz « pas besoin blabla », mais cette classe gère l’envoie d’images, de sons en plus de simple paramètres POST classique. Vous faites moins les malins hein :) Et si je vous dit qu’elle gère aussi si la requête doit être fait en mode synchrone ou asynchrone hein ? Ça t’en bouche un coin ?

    Bah en fait elle est très simple, j’ai juste joué au légo avec les classes Apple, mais c’est un lego qui me sert pas mal.

    Voici un exemple d’utilisation, ce code est tiré de l’exemple que j’ai fait pour vous, disponible en téléchargement :

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    
    -(IBAction) send
    {
    // Crée la requete en mode asynchrone
    HttpRequest *masuperRequete = [[HttpRequest alloc] initHttpRequest:formUrlAsk.text isSynchronous:false];
     
    // Ajoute un parametre POST['cleParam'];
    [masuperRequete addParam:@"cleParam" valeurs:formParam.text];
     
    // Ajoute un fichier Image. Les parametres seront sous la forme file1, file2, file3 .. etc
    [masuperRequete addImage:imageTmp.image];
     
    // ajoute un son
    // On doit recuperer les données du son sous la forme d'un NSDATA
    // Ici le son est distant .. on le recupère donc avec the super classe en mode syncrhone
    HttpRequest *sousReq = [[HttpRequest alloc] initHttpRequest:formUrlSound.text isSynchronous:true];
    NSData * dataSound = [sousReq send];
     
    // Recupere le nom du son
    NSArray * mots = [formUrlSound.text componentsSeparatedByString:@"/"];
    NSString *nameoffile = [mots lastObject];
     
    [masuperRequete addSound:dataSound nameoffile:nameoffile nameinform:@"mamusique"];
     
    // Envoie la superRequete
    masuperRequete.delegate = self;
    [masuperRequete send];
    }
     
    // y a un delegate pour recup le retour de la requete en mode asynchrone
    -(void)downloadFinish:(NSMutableData *)data
    {
    NSLog(@"telechargement termine");
    }

    Maintenant voici le code source complet de l’exemple

    Exemple de la classe HTTPRequest

    Pour récupérer les données par la suite, rien de plus simple tout est dans $_POST et $_FILES.

    maj : voilà le code source du fichier php que j’ai utilisé :

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    
     
    <?php
     
    $content_dir = 'upload/';
     
    if(count($_POST) > 0 || count($_FILES) > 0)
    {
     
     
     
     
    	if(count($_POST) > 0)
    	{
    		echo "variable POST : \n";
    		foreach($_POST as $cle=>$val)
    			echo $cle . ' => ' . $val ."\n";
     
    		if(isset($_POST['monson']))
    		{
    			$test = base64_decode($_POST['monson']);
     
    			$file = fopen("upload/son.caf","w+");
     
    			fwrite($file,$test);
     
    			fclode($file);
    		}
     
    	}
     
    	if(count($_FILES) > 0)
    	{
    		echo "variable FILES : \n";
    		foreach($_FILES as $cle=>$image)
    		{
     
    			$tmp_file = $image['tmp_name'];
     
    			if(!empty($tmp_file))
    			{
     
     
    				if( !is_uploaded_file($tmp_file) )
    				{
    					exit("Le fichier est introuvable");
    				}
     
    				// on vérifie maintenant l'extension
    				$type_file = $image['type'];
     
    				if( !strstr($type_file, 'jpg') &#038;&#038; !strstr($type_file, 'jpeg') &#038;&#038; !strstr($type_file, 'bmp') &#038;&#038; !strstr($type_file, 'png') &#038;&#038; !strstr($type_file, 'gif') )
    				{
    					//exit("Le fichier n'est pas une image");
    				}
     
    				// on copie le fichier dans le dossier de destination
    				$name_file = $image['name'];
     
    				echo $cle. " => " .$name_file ." reçu \n";
     
    				if( !move_uploaded_file($tmp_file, $content_dir . $name_file) )
    				{
    					exit("Impossible de copier le fichier dans $content_dir");
    				}
     
    			}
    	}
    }
    }
    else
    {
    	 $rep = "upload/";
    	$dir = opendir($rep);
     
    	while ($f = readdir($dir)) {
      	 if(is_file($rep.$f)) {
        		echo "<li>Nom : ".$f;
    		echo '<a href="upload/'.$f.'"> DL </a>';
          		echo "<li>Taille : ".filesize($rep.$f)." octets";
          		echo "<br /><br />";
       		}
    	}
    }
     
     ?>

    Précisons quand même que ma classe est en alpha, certaines fonctionnalités ne sont pas implémentés. Je pense notamment à la gestion des erreurs, le delegate qui donne le taux de progression de l’upload etc. Je vous laisse le faire :p

    Enjoy !

    Image representing Apple as depicted in CrunchBase

    Image via CrunchBase

    Billet écrit dans : Mobile, iPhone 09.07.2009 10 Réactions !!
  • Billet écrit dans : Mobile, iPhone 06.04.2009 7 Réactions !!

    Bonjour,

    Voici juste un petit « How to » pour comprendre et jour avec les delegate sur cocoa.

    Admettons vous avez une classe « ListingController » qui hérite d’une UIViewController qui gère une liste d’élément et que vous avez une classe « DetailController » qui hérite aussi d’une UIViewController mais qui donne le detail de l’élément cliqué.

    Vous voulez que lorsqu’on click sur un bouton posé sur la vue Détail revenir à la liste principal, puis la recharger. Revenir à la vue principal est assez simple il suffit de crée une méthode « IBAction » dans le controller Detail, liée le bouton à cette méthode via Interface builder puis écrire  :

    1
    2
    3
    
    -(IBAction)goHome {
    [self.view removeFromSuperview];
    }

    Et le tour est joué mais bon, la liste n’est pas rechargé pour autant et il n’y a pas eu la levé d’un évènement pour la classe « Liste ». C’est là que les delegate peuvent nous être utile.

    Le principe est de définir des méthodes sur la classe de Detail puis les appeller/utiliser lors du click mais c’est la classe Liste qui les implémentera effectivement.

    Voici la marche à suivre :

    1. Dans la classe Detail : Définir une ou plusieurs méthodes dite « delegate » qui devront être implémenter. On appelle ce genre de déclaration un « protocole ».
    2. Dans la classe Detail : Définir une propriété de classe de type « id » qui utilise le protocole. Cette propriété représente un lien vers la classe « parente » qui implémentera effectivement notre protocole.
    3. Dans la classe Detail : Appeller lors du click les méthodes « delegate » sur notre protocole.
    4. Dans la classe Liste : Implémenter les méthodes delegate dans notre classe « parente ».

    Etape 1 :

    Dans le fichier « DetailController.h », juste après les #import et avant @interface DetailController : UIViewController { } :

    1
    2
    3
    4
    
    @protocol DetailControllerDelegate
    @required
    -(void)RetourListe;
    @end

    Etape 2 :

    Toujours dans le fichier « DetailController.h », après « @interface DetailController : UIViewController { » nous définissons une propriété que nous appellerons « delegate » :

    1
    
    id delegate;

    puis après l’accolade définissant l’interface :

    1
    2
    3
    
    @property (nonatomic,assign) id < DetailControllerDelegate > delegate;
     
    @end

    Notre propriété « delegate » est de type « id » mais « implémente » le protocole précédement utilisé.

    Etape 3 :

    Nous avons définit une propriété dans le fichier « .h », il faut maintenant s’en servir dans notre fichier « DetailController.m » :

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    #import "DetailController.h"
    @implementation DetailController
    @synthesize delegate; //synthetisé une propriété signifie que le sdk créera les getters/setters pour nous
    -(IBAction)goHome
    {
    	NSLog(@"Go home Liste");
    	[self.delegate RetourListe]; // dispatch l'évènement à la classe parente.
    	[self.view removeFromSuperview]; // supprime la vue courante
    }

    C’est fini pour notre classe Detail  ! Vous remarquerez qu’à aucun moment il n’y a de lien vers la classe « Liste ». Le couplage est donc très faible entre ces classes. Ce principe de couplage faible est assez puissant si on y réfléchi à deux fois vu que nos classes sont, de fait, totalement indépendantes vis à vis de leur « parent » (ou du contexte d’execution pour être plus bien parlant). Bon bref ça c’était le coup de pub raté pour la puissance du modèle objet.

    Etape 4

    Implémentons les méthodes ! Dans le fichier « ListingController.h » nous déclarons notre interface comme ceci :

    1
    2
    3
    
    @interface ListingController : UIViewController < DetailControllerDelegate > {
    // some code
    }

    Et dans notre fichier « ListingController.m » il suffit d’implémenter la méthode « RetourListe ». Surtout, ne pas la déclarer dans l’interface (le fichier .h) sinon le programme se mélangera les pinceaux ! (Oui, vous utilisez deux méthodes avec le même nom ayant des portés différentes ..)

    1
    2
    3
    4
    5
    
    -(void)RetourListe
    {
        NSLog("coucou");
        // some code
    }

    Edit : Oups, erreur. On crée la méthode mais à un aucun moment on dit que notre classe Listing va implémenter les méthodes de detail hormis dans la déclaration (fichier.h). Il faut donc qu’à notre objet « DetailController », juste après qu’il soit instanciée, au moment du click par exemple faire un :

    1
    2
    
    DetailController*myView = [[DetailControlleralloc] initWithNibName:@"DetailView" bundle:[NSBundle mainBundle]];
    myView.delegate = self;

    On définit que c’est la classe Listing (self) va implémenter les méthodes delegate de détail.

    Et voilà, normallement ça doit marcher.

    Ce « How to » a été écrit à partir d’un projet personnel, je ne pourrais donc pas donnée des sources qui utilisent ce concept. A l’heure où j’écrit ce billet je n’ai pas de Mac à ma disposition.

    Billet écrit dans : Mobile, iPhone 06.04.2009 7 Réactions !!
  • Billet écrit dans : Mobile, iPhone 18.03.2009 Aucune réponse à cet article.

    Aujourd’hui, j’ai bataillé pour lancer un mp3 au lancement d’une application. Tellement bataillé que je vais mettre ici le code qui va bien pour que je puisse le retrouver rapidement :) Donc peu d’explication, ceci n’est pas un tutorial.

    1. Inclure le framework AudioToolBox & AVFoundation
    2. Faire les imports suivants : #import &lt;AVFoundation/AVFoundation.h&gt; #import &lt;AudioToolbox/AudioToolbox.h&gt;
    3. Inclure le fichier à jouer dans le projet dans le dossier « ressources »
    4. Déclarer une propriété de classe AVAudioPlayer * audioPlayer;

    Et voici le code qui va bien :

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    
    	// Initialise un contexte Audio
    	AudioSessionInitialize (
    							NULL,                          // 'NULL' to use the default (main) run loop
    							NULL,                          // 'NULL' to use the default run loop mode
    							NULL,  // a reference to your interruption callback
    							self                       // data to pass to your interruption listener callback
    							);
     
    	// Definit quel type de son on va joué
    	UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback;
    	AudioSessionSetProperty (
    							 kAudioSessionProperty_AudioCategory,
    							 sizeof (sessionCategory),
    							 &#038;sessionCategory
    							 );
     
    	// Définit quel fichier on utilise pour le son
    	NSData *soundFileData;
    	soundFileData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"music.mp3" ofType:NULL]]];
     
    	// Initialise notre lecteur avec les données du fichiers son à jouer
    	audioPlayer = [[AVAudioPlayer alloc] initWithData:soundFileData error:NULL];
     
    	// Precharge le son
    	if(!([audioPlayer prepareToPlay])){
    		NSLog(@"myAudioPlayer:prepareToPlay returned FALSE");
    	}
     
    	// Définit le delegate sur la classe courante
    	audioPlayer.delegate = self;
     
    	// Définit le volume
    	[audioPlayer setVolume:1.0];
     
    	// Joue le son !
    	[audioPlayer play];

    Voilà, la seul différence avec les codes que l’on peut trouver un peu partout est l’ajout du Session Audio. Si je l’initialise pas le son ne fonctionne que sur le simulateur et pas sur le mobile. Je ne sais pas trop pourquoi.

    Merci à fpillet du channel irc #iphonedev sur freenode pour son aide.

    Billet écrit dans : Mobile, iPhone 18.03.2009 Aucune réponse à cet article.
CV Guillaume chave