Garder des WebView en mémoire au changement de View

sonizefsonizef Membre
mai 2014 modifié dans API UIKit #1

Bonjour,


 


comme je l'avais expliqué sur l'un de mes anciens postes j'essaye de créer une application avec une WebView par View (et je change de View en élidant celle-ci).


Seulement à  chaque fois que je change de View je suis obligé de recharger ma webview ... 


 


Sous Android c'est ".setOffscreenPageLimit()" avec en argument le nombre de page que je souhaite garder en mémoire. Est ce qu'il y'a un équivalent chez Apple ?


 


J'ai déjà  tenté de remplacer :



@property (weak, nonatomic) IBOutlet UIWebView *webContact;
@property (weak, nonatomic) IBOutlet UIWebView *webEven;
@property (weak, nonatomic) IBOutlet UIWebView *webBus;

par 



@property (strong, retain) IBOutlet UIWebView *webContact;
@property (strong, retain) IBOutlet UIWebView *webEven;
@property (strong, retain) IBOutlet UIWebView *webBus;

Mais rien ne change.


 


J'ai un peu de mal avec ce langage alors un peu d'aide est toujours la bienvenu !


 


Merci.


Réponses

  • samirsamir Membre

    Salut,


     


    setOffscreenPageLimit() est une propertie du composant ViewPager. Ce qu'il faut chercher c'est l'équivalent du ViewPage == UIPageViewController. 


     


    Sous iOS, le UIPageViewController utilise plutôt le pattern delegate/data source pour demander la page suivante et la page précédente.


     


    https://developer.apple.com/library/ios/documentation/uikit/reference/UIPageViewControllerClassReferenceClassRef/UIPageViewControllerClassReference.html


     


    https://developer.apple.com/library/ios/documentation/uikit/reference/UIPageViewControllerDataSourceProtocolRef/UIPageViewControllerDataSource.html#//apple_ref/occ/intf/UIPageViewControllerDataSource


     


    J'espère que ça répond à  ta question.


  • sonizefsonizef Membre
    mai 2014 modifié #3

    Salut,


     


    Et bien j'étais sur la bonne voie (ViewPager == UIPageViewController), j'étais même tombé sur la Doc d'Apple comme les liens que tu m'a donné.


     


    Mais même avec cette doc je n'arrive pas à  trouver la solution à  mon problème :/ 


     


    Tu me parles des pattern delegate / data source et c'est certainement de ce coté qu'il faut regarder, mais je n'y connais rien à  ce niveau ?


    En tous cas, sauf erreur de ma part, il n'existe aucune méthode à  appliquer à  notre UIPageViewController pour lui demander combien de View mettre en mémoire ..


     


    Merci d'avoir pris le temps de répondre


  • J'ai continué à  chercher, mais sans résultat, personne n'a d'autre piste ? Ou quelqu'un peut m'aiguiller d'avantage sur la piste en cours ? 


    En vous remerciant


  • samirsamir Membre

    Salut,


     


    Oui tu es sur la bonne piste, UIUPageViewController. C'est lui qui va géré le nombre de contrôleurs/vues en mémoires. A chaque fois qu'il veux afficher une nouvelle vue, il demande à  sa source de donnée (un objet qui se conforme au protocol UIPageViewControllerDataSource) le prochain contrôleurs et le précédent.


     


    Y a plein de tutorials sur internet si tu n'arrives pas à  le mettre en oeuvre toi même.


    http://www.techotopia.com/index.php/An_Example_iOS_5_iPhone_UIPageViewController_Application




  • Salut,


     


    Oui tu es sur la bonne piste, UIUPageViewController. C'est lui qui va géré le nombre de contrôleurs/vues en mémoires. A chaque fois qu'il veux afficher une nouvelle vue, il demande à  sa source de donnée (un objet qui se conforme au protocol UIPageViewControllerDataSource) le prochain contrôleurs et le précédent.


     


    Y a plein de tutorials sur internet si tu n'arrives pas à  le mettre en oeuvre toi même.


    http://www.techotopia.com/index.php/An_Example_iOS_5_iPhone_UIPageViewController_Application




     


    Merci pour ta réponse, mais le tuto que tu m'as donné sert à  mettre en oeuvre une application multipage à  l'aide d'un PageViewController ? Mais je l'ai déjà  fait ^^


    Mais du coup je ne n'arrive toujours pas à  mettre un vue en mémoire (puisque j'avais regardé la doc sur UIPageViewController)  :'(


     


    Merci quand même ... (à  moins que j'ai loupé quelques chose dans ta réponse)

  • samirsamir Membre


    Mais du coup je ne n'arrive toujours pas à  mettre un vue en mémoire (puisque j'avais regardé la doc sur UIPageViewController)  :'(




     


    Je ne comprends pas ce que tu veux dire par mettre une vue en mémoire ? 


    Tu peux monter ton code stp et dire ce qui ne marche pas ou bien expliquer ce que tu veux avoir comme visuel ( chargé une webView,...)



  • Je ne comprends pas ce que tu veux dire par mettre une vue en mémoire ? 


    Tu peux monter ton code stp et dire ce qui ne marche pas ou bien expliquer ce que tu veux avoir comme visuel ( chargé une webView,...)




     


    Et bien en fait j'ai mon application multi page qui fonctionne, en les appelant les vues de cette façon : 



    - (PageContentViewController *)viewControllerAtIndex:(NSUInteger)index
    {
    if (index >= 4) {
    return nil;
    }

    if(index == 0){
    // Create a new view controller and pass suitable data.
    PageContentViewController *pageContentViewController = [self.storyboard instantiateViewControllerWithIdentifier:@accueil];
    pageContentViewController.pageIndex = index;

    return pageContentViewController;
    }

    if(index == 1){
    // Create a new view controller and pass suitable data.
    PageContentViewController *pageContentViewController = [self.storyboard instantiateViewControllerWithIdentifier:@contact];
    pageContentViewController.pageIndex = index;

    return pageContentViewController;
    }

    if(index == 2){
    // Create a new view controller and pass suitable data.
    PageContentViewController *pageContentViewController = [self.storyboard instantiateViewControllerWithIdentifier:@even];
    pageContentViewController.pageIndex = index;

    return pageContentViewController;
    }

    if(index == 3){
    // Create a new view controller and pass suitable data.
    PageContentViewController *pageContentViewController = [self.storyboard instantiateViewControllerWithIdentifier:@bus];
    pageContentViewController.pageIndex = index;

    return pageContentViewController;
    }

    return nil;
    }

    Le problème c'est qu'à  chaque fois que je change de vue (en glissant un écran donc) je suis obligé de la recharger ... et je voudrai qu'une fois qu'une vue est chargée totalement, la garder en "mémoire" afin de ne plus avoir besoin de la recharger par la suite, et ainsi rendre la navigation plus fluide ...


     


    Est-ce plus clair ?


     


    Merci

  • AliGatorAliGator Membre, Modérateur
    mai 2014 modifié #9
    Bah il suffit de la garder qqpart si tu veux la garder, non ?

    1) Solution 1, tu crées une propriété de type PageContentViewController pour chaque page. Dans chacun de tes "if", au lieu de faire un "instantiaiteViewControllerWithIdentifier:" systématiquement et donc de réallouer une nouvelle instance à  chaque fois, tu regardes si la @property correspondante est nil. Si elle est nil tu instancies le ViewController et le garde de côté dans la @property... mais si elle n'est pas nil et que tu as déjà  le PageContentViewController pour cette page, bah tu le réaffiches

    2) Solution 2 : même principe mais au lieu d'avoir une @property par page, tu mets tout ça dans un NSArray

    3) Solution 3, la plus propre, tu utilises un objet NSCache (qui fonctionne un peu comme un NSDictionary, mais est justement fait pour gérer les aspects cache (= si jamais tu as un Memory Warning il va se vider pour libérer de la mémoire, etc, etc)
     
    // Dans ton fichier ViewController.m
    @interface ViewController ()
    @property(strong) NSCache* pagesCache;
    @end

    @implementation ViewController
    - (id)init {
    self = [super init];
    if (self) {
    // Instancier un NSCache vide prêt à  garder les PageContentVC de côté
    self.pagesCache = [[NSCache alloc] init];
    }
    return self;
    }

    - (PageContentViewController *)viewControllerAtIndex:(NSUInteger)index
    {
    if (index >= 4) return nil;
    // Tableau C des noms des Nib à  utiliser selon l'index
    static NSString* const nibNames[] = { @accueil, @contact , @even, @bus };

    NSString* cacheKey = @(index);
    // On regarde dans le cache si on n'a pas déjà  un PageContentVC pour cet index
    PageContentViewController* pageContentVC = [self.cache objectForKey:cacheKey];
    if (!pageContentVC) {
    // Si on n'en n'a pas, on le crée, en utilisant le nibName correspondant à  l'index
    NSString* nibName = nibNames[index];
    pageContentVC = [self.storyboard instantiateViewControllerWithIdentifier:nibName];
    pageContentVC.pageIndex = index;
    // Et on le met dans le cache pour les prochaines fois
    [self.cache setObject:pageContentVC forKey:cacheKey];
    }

    // Que le PageContentVC ait été directement retrouvé dans le cache ou qu'il ait été créé pour la première fois, on le retourne dans tous les cas.
    return pageContentViewController;
    }
  • sonizefsonizef Membre
    mai 2014 modifié #10


    Bah il suffit de la garder qqpart si tu veux la garder, non ?


    1) Solution 1, tu crées une propriété de type PageContentViewController pour chaque page. Dans chacun de tes "if", au lieu de faire un "instantiaiteViewControllerWithIdentifier:" systématiquement et donc de réallouer une nouvelle instance à  chaque fois, tu regardes si la @property correspondante est nil. Si elle est nil tu instancies le ViewController et le garde de côté dans la @property... mais si elle n'est pas nil et que tu as déjà  le PageContentViewController pour cette page, bah tu le réaffiches


    2) Solution 2 : même principe mais au lieu d'avoir une @property par page, tu mets tout ça dans un NSArray


    3) Solution 3, la plus propre, tu utilises un objet NSCache (qui fonctionne un peu comme un NSDictionary, mais est justement fait pour gérer les aspects cache (= si jamais tu as un Memory Warning il va se vider pour libérer de la mémoire, etc, etc)

     



    @interface Blah
    @property(strong) NSCache* pagesCache;
    @end
    @implementation Blah
    - (id)init {
    self = [super init];
    if (self) {
    self.pagesCache = [[NSCache alloc] init];
    }
    }

    - (PageContentViewController *)viewControllerAtIndex:(NSUInteger)index
    {
    if (index >= 4) return nil;
    static NSString* const nibNames = { @accueil, @contact , @even, @bus };

    NSString* cacheKey : @(index);
    PageContentViewController* pageContentVC = [self.cache objectForKey:cacheKey];
    if (!pageContentVC) {
    NSString* nibName = nibNames[index];
    pageContentVC = [self.storyboard instantiateViewControllerWithIdentifier:nibName];
    pageContentVC.pageIndex = index;
    [self.cache setObject:pageContentVC forKey:cacheKey];
    }

    return pageContentViewController;
    }



    Salut, toutes tes réponses sembles répondre à  mon problème ... En copiant (bêtement) je l'avoue ton bout de code, puisque je n'y connais pas grand chose) je me retrouve avec pas mal d'erreur; alors je vais essayer ta solution 1, dommage la 3 était plus propre !



    @interface ViewController ()
    @property(strong) NSCache* pagesCache;
    @end

    @implementation ViewController

    - (id)init
    {
    self = [super init];
    if (self) {
    self.pagesCache = [[NSCache alloc] init];
    }
    }



    - (void)viewDidLoad
    {
    [super viewDidLoad];

    // Create page view controller
    self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:@PageViewController];
    self.pageViewController.dataSource = self;

    PageContentViewController *startingViewController = [self viewControllerAtIndex:0];
    NSArray *viewControllers = @[;startingViewController];
    [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];

    // Change the size of page view controller
    self.pageViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - 0);

    [self addChildViewController:_pageViewController];
    [self.view addSubview:_pageViewController.view];
    [self.pageViewController didMoveToParentViewController:self];

    }

    - (void)didReceiveMemoryWarning
    {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
    }

    - (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController
    {
    return 4;
    }

    - (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController
    {
    return 0;
    }

    - (PageContentViewController *)viewControllerAtIndex:(NSUInteger)index
    {
    if (index >= 4) {
    return nil;
    }
    static NSString* const nibNames = { @accueil, @contact , @even, @bus };

    NSString* cacheKey : @(index);
    PageContentViewController* pageContentVC = [self.cache objectForKey:cacheKey];
    if (!pageContentVC) {
    NSString* nibName = nibNames[index];
    pageContentVC = [self.storyboard instantiateViewControllerWithIdentifier:nibName];
    pageContentVC.pageIndex = index;
    [self.cache setObject:pageContentVC forKey:cacheKey];
    }
    return pageContentVC;
    }    

    Les screens des erreurs sont en pièces jointes


     


    Merci


  • La solution n°1 fonctionne alors merci ! :D  


    Je répond sur un nouveau post pour que ce soit plus clair, voici donc le code si ça peut en aider d'autre :



    @interface ViewController ()

    @property PageContentViewController *pageAccueil;
    @property PageContentViewController *pageContact;
    @property PageContentViewController *pageEven;
    @property PageContentViewController *pageBus;

    @end


    - (PageContentViewController *)viewControllerAtIndex:(NSUInteger)index
    {
    if (index >= 4) {
    return nil;
    }

    if(index == 0){
    if(_pageAccueil == nil){
    _pageAccueil = [self.storyboard instantiateViewControllerWithIdentifier:@accueil];
    _pageAccueil.pageIndex = index;
    }

    return _pageAccueil;
    }

    if(index == 1){
    if(_pageContact == nil){
    _pageContact = [self.storyboard instantiateViewControllerWithIdentifier:@contact];
    _pageContact.pageIndex = index;
    }

    return _pageContact;
    }

    if(index == 2){
    if(_pageEven == nil){
    _pageEven = [self.storyboard instantiateViewControllerWithIdentifier:@even];
    _pageEven.pageIndex = index;
    }

    return _pageEven;
    }

    if(index == 3){
    if(_pageBus == nil){
    _pageBus = [self.storyboard instantiateViewControllerWithIdentifier:@bus];
    _pageBus.pageIndex = index;
    }

    return _pageBus;
    }

    return nil;
    }
  • AliGatorAliGator Membre, Modérateur
    Pour la solution 3 j'ai tapé entièrement au kilomètre (surtout la méthode de delegate), sans aucune vérification, donc oui il y a sûrement des fautes de frappe & co, ça ne m'étonne pas trop. L'intérêt était surtout de te donner des grandes lignes, l'idée générale, pour que tu cherches à  comprendre ce que fais le code et adaptes à  tes besoins. Pas à  juste copier/coller sans comprendre. D'autant que le code en question n'est pas vraiment méchant.


  • Pour la solution 3 j'ai tapé entièrement au kilomètre (surtout la méthode de delegate), sans aucune vérification, donc oui il y a sûrement des fautes de frappe & co, ça ne m'étonne pas trop. L'intérêt était surtout de te donner des grandes lignes, l'idée générale, pour que tu cherches à  comprendre ce que fais le code et adaptes à  tes besoins. Pas à  juste copier/coller sans comprendre. D'autant que le code en question n'est pas vraiment méchant.




     


    Oui oui je me doute bien, j'ai fais quelques adaptations et j'ai compris l'idée général !


    Seulement ne connaissant pas du tout ce langage j'ai un peu de mal avec les erreurs entre les types de variables (NSString et NSUInteger par exemple), l'erreur sur @contact et pas les autres pour nibNames et également à  propos de la fonction - (id)init qui me sort une erreur que je connais pas non plus.


     


    Je pense rester sur la solution 1 du coup puisqu'elle me semble assez efficace, mais dommage pour la solution 3 qui été intéressante !


     


    Enfin bref en te remerçiant

  • AliGatorAliGator Membre, Modérateur
    mai 2014 modifié #14
    Alors les erreurs dans mon code:
    • dans le init j'ai oublié le "return self;". C'est ce que voulais dire le message en disant qu'il était arrivé à  la fin de la fonction en oubliant de retourner un truc alors que c'était une fonction non-void (= qui est déclaré avec un type de retour autre que "void" " ici "id" " donc qui est sensé retourner qqch.
    • Quant à  ma déclaration de la variable nibNames, j'ai oublié les [] après le nom de la variable ("static NSString* const nimNames[] = { ... }") pour en faire un simple tableau C. C'est pour ça qu'il y a l'erreur à  la fois sur la ligne où est déclaré nibNames mais ensuite aussi sur toutes les autres lignes qui tentent de l'utiliser
    • j'avais mis un ":" au lieu d'un "=" quand j'ai voulu déclarer la variable cacheKey (erreur de frappe)
    • Et enfin, j'ai appelé ma propriété "pagesCache" dans le @interface et ai bien utilisé ce nom dans le init, mais après dans le reste du code j'ai utilisé le nom "self.cache" au lieu de "self.pagesCache", j'ai pas été très cohérent ^^ Il suffit de choisir l'un des 2 noms et de s'y tenir dans tout le code.
  • Oui ça doit surement être ça ! 


     


    Je me doute que ce sont des erreurs d'inattention seulement je ne connais pas du tout ce langage alors après la moindre erreur devient vite un calvaire x)


     


    Mais grâce à  toi je connais à  présent le NSCache qui est très intéressant


  • AliGatorAliGator Membre, Modérateur
    mai 2014 modifié #16
    Pour info j'ai édité mon message #14 ci-dessous pour donner les explications sur chacune des erreurs dans mon code, et j'ai corrigé mon code dans le message #9.


  • Pour info j'ai édité mon message #14 ci-dessous pour donner les explications sur chacune des erreurs dans mon code, et j'ai corrigé mon code dans le message #9.




     En te remerciant ! Je regarder ça en détail dans la semaine

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