IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Objective-C Discussion :

NSThread et NSGenericException


Sujet :

Objective-C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 8
    Par défaut NSThread et NSGenericException
    Bonjour,

    cela fait plusieurs heures que j'essais de résoudre un problème sans succès.
    Je souhaite donc obtenir l'avi de personne plus expérimenté.

    Je développe une application iPhone, le principe est de réaliser une liste d'image miniature. Pour cela, j'utilise des thread pour chaque image, se qui me permet de les charger en asynchrone.

    J'utilise une vue de type UIScrollView pour n'afficher que 9 images par page.
    Au bout d'un certain nombre de page(toujours différent) mon application plante et m'affiche ceci dans le terminal:


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <CALayerArray: 0x12a330> was mutated while being enumerated.'
    *** First throw call stack:
    (0x3414c8bf 0x3439c1e5 0x3414c3e3 0x3750d34f 0x3750cec3 0x375f226b 0x376b45ef 0x34147813 0x3414072f 0x340a5f0d 0x3750cf21 0x376b45ef 0x34147813 0x3414072f 0x340a5f0d 0x3750cf21 0x374f4107 0x30927df3 0x34120553 0x341204f5 0x3411f343 0x340a24dd 0x340a23a5 0x30926fcd 0x37523743 0x291d 0x28dc)
    D'après mes tests il se pourrais que cela vienne de mon appelle à l'objet self, mais je ne sais pas quoi faire.


    Mes thread sont appeler comme ceci dans une boucle for :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    [NSThread detachNewThreadSelector:@selector(startTheBackgroundLoadImage:) toTarget:self withObject:dictionary];
    et :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    - (void)startTheBackgroundLoadImage:(id) dictionary {
        @synchronized(self) {
     
                NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
     
                CGRect frameThumbnail = CGRectMake([[dictionary objectForKey:@"x"] floatValue], [[dictionary objectForKey:@"y"] floatValue], WIDTH, HEIGHT);
                NSUInteger index = [[dictionary objectForKey:@"index"] integerValue];
     
                ThumbnailView * thumbnail = [ [ThumbnailView alloc] initWithStringURL:[[images objectAtIndex:index] objectForKey:@"thumbnails"] ];
     
                thumbnail.frame = frameThumbnail;
                thumbnail.index = index;
                [self addSubview:thumbnail];
     
                [thumbnail release];
                [pool release];
            }
        }
    }
    C'est difficile a expliquer, j'espère avoir réussit à me faire comprendre.
    Quelqu'un aurait une idée ?

  2. #2
    Membre Expert
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    2 968
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 2 968
    Par défaut
    Citation Envoyé par chjeremy Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <CALayerArray: 0x12a330> was mutated while being enumerated.'
    *** First throw call stack:
    (0x3414c8bf 0x3439c1e5 0x3414c3e3 0x3750d34f 0x3750cec3 0x375f226b 0x376b45ef 0x34147813 0x3414072f 0x340a5f0d 0x3750cf21 0x376b45ef 0x34147813 0x3414072f 0x340a5f0d 0x3750cf21 0x374f4107 0x30927df3 0x34120553 0x341204f5 0x3411f343 0x340a24dd 0x340a23a5 0x30926fcd 0x37523743 0x291d 0x28dc)
    Cette exception dit clairement le problème :
    vous appelez directement ou indirectement une fonction qui modifie les layers (CALayerArray) de votre hiérarchie visuelle dans un thread alors que le thread principal a besoin de traverser cette hiérarchie pour rafraîchir l'écran.

    Solution: cet appel est probablement le addSubview et
    - soit mettez un verrou autour de cet appel
    (@synchronized, NSLock, … ), verrou qui sera aussi mis dans la fonction de dessin du thread principal,
    - soit ajoutez la subview en appelant performSelectorOnMainThread:withObject:waitUntilDone,
    - soit utilisez une NSOperation qui sera mise en queue sur la mainQueue (celle du thread principal).

    Cette dernière opération peut être la plus simple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    [[NSOperationQueue mainQueue] addOperationWithBlock:
     ^(void) { [self addSubview:thumbnail]; }
    ];

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 8
    Par défaut
    Merci pour votre réponse JeitEmgie, je débute en objective-c je ne voyais pas ce qu'il voulait dire par CALayerArray. Je vous remercie de vos éclaircissements. Je vais essayer les différentes solutions proposé.

    Je vous tiens au courant.

  4. #4
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 8
    Par défaut
    Citation Envoyé par JeitEmgie Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    [[NSOperationQueue mainQueue] addOperationWithBlock:
     ^(void) { [self addSubview:thumbnail]; }
    ];
    Bonjour, je reviens pour vous tenir au courant, j'ai bien utiliser la mise en queue pour faire fonctionner correctement mes thread.

    Cependant je rencontre un nouveau problème et j'aimerais profiter de votre expérience.

    Comme je l'ai dit j'utilise une UIScrollView en mode pagingEnabled = yes pour afficher 9 miniatures d'image par page.

    Le problème est qu'a un instant T je crois que mon application utilise trop de mémoire, car la méthode didReceiveMemoryWarning ce lance.

    Le nombre de thread lancé est de 9 + le thread principal.
    Pour illustré un peu voici une application qui ressemble beaucoup à se que j'essaie de faire : http://itunes.apple.com/us/app/backg...402686240?mt=8

    Autre point à savoir, chaque miniature est en faite un uiButton pour pouvoir effectuer un touchesBegan pour agrandir l'image.

    Quelqu'un aurait un conseille ou des bonne pratique à appliquer pour ne pas tomber en "memory warning"

    Merci beaucoup pour votre aide.

  5. #5
    Membre Expert
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    2 968
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 2 968
    Par défaut
    Citation Envoyé par chjeremy Voir le message
    Quelqu'un aurait un conseille ou des bonne pratique à appliquer pour ne pas tomber en "memory warning"
    Libérer les objets qui ne sont pas visibles.

  6. #6
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 8
    Par défaut
    C'est effectivement ce que je me suis mi à penser hier. Je travaille dessus.

    Merci beaucoup

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo