2015-08-17 2 views
0

У меня есть UICollectionView, который использует - (void)scrollViewDidScroll:(UIScrollView *)scrollView, чтобы определить, когда пользователь прокрутил страницу вниз.Выполнение селектора на superView

У владельца моего UICollectionView есть метод, который отправляет команду серверу и запрашивает больше данных.

Что я хочу сделать, это выполнить селектор на собственнике (мой диспетчер представлений) с моего UICollectionView, и в частности, с scrollViewDidScroll.

Я пытаюсь сделать это, используя следующий код:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{ 
    CGFloat offsetY = scrollView.contentOffset.y; 
    CGFloat contentHeight = scrollView.contentSize.height; 
    if (offsetY > contentHeight - scrollView.frame.size.height) 
    { 
     [[self superView] performSelector:@selector(onScrolledToBottom) withObject:nil]; 
    } 
} 

Примечание: селектор onScrolledToBottom является SEL свойство моей UICollectionView.

Ошибка я получаю говорит:

-[UIView onScrolledToBottom]: unrecognized selector sent to instance 0x7fc641e76e00 
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIView onScrolledToBottom]: unrecognized selector sent to instance 0x7fc641e76e00' 

EDIT

Я раздели свой код, чтобы уместить на этот вопрос.

У меня есть followin в моем ViewController.m

.... 

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view, typically from a nib. 
    [self initCollectionView]; 
} 
.... 

- (void) getMoreInfo{ 
    NSLog(@"Getting more info"); 
} 

- (void) initCollectionView{ 
    UICollectionViewFlowLayout* flowLayout = [[UICollectionViewFlowLayout alloc]init]; 
    flowLayout.itemSize = CGSizeMake(50.0, 60.0); 
    flowLayout.sectionInset = UIEdgeInsetsMake(20, 0, 20, 0); 
    [flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical]; 
    flowLayout.headerReferenceSize = CGSizeMake(320.f, 30.f); 

    myCollectionView *mVC = [myCollectionView alloc] init: self.view: flowLayout: @selector(getMoreInfo)]; 
} 

И для моих myCollectionView в .h и .m файлы выглядят следующим образом:

#import <UIKit/UIKit.h> 

@interface myCollectionView : UICollectionView<UIScrollViewDelegate, UICollectionViewDelegate, UICollectionViewDataSource>{ 
    UIView *parentView; 
    SEL onScrolledToBottom; 
} 

@property UIView *parentView; 
@property SEL onScrolledToBottom; 

- (id)init: (UIView*) parent: (UICollectionViewLayout *)layout: (SEL)onScrolledToBottomSEL; 
@end 

и

#import "myCollectionView.h" 

@implementation myCollectionView 

@synthesize parentView = parentView; 
@synthesize onScrolledToBottom = onScrollToBotton; 

- (id)init: (UIView*) parent: (UICollectionViewLayout *)layout: (SEL)onScrolledToBottomSEL{ 
    self = [super initWithFrame: CGRectMake(0.0f, 0.0f, parent.frame.size.width, parent.frame.size.height) collectionViewLayout: layout]; 
    if (self) { 
     parentView = parent; 
     self.delegate = self; 
     self.dataSource = self; 
     onScrolledToBottom = onScrolledToBottomSEL; 
    } 

    return self; 
} 
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{ 
    CGFloat offsetY = scrollView.contentOffset.y; 
    CGFloat contentHeight = scrollView.contentSize.height; 
    if (offsetY > contentHeight - scrollView.frame.size.height) 
    { 
     [parentView performSelector:@selector(onScrolledToBottom) withObject:nil]; 
    } 
} 
+1

Можете ли вы показать декларацию метода 'onScrolledToBottom' – Saif

+0

@saif Я не совсем уверен, что вы имеете в виду. Вы имеете в виду, если я поместил его в '.h' моего ViewController? – vaid

+0

Да, поместите файл заголовка. – Saif

ответ

2

Вы получаете супервизор вместо родительского контроллера, это один. Во-вторых, вы не должны пытаться это сделать. Вместо этого используйте протокол и передайте свой контроллер в качестве делегата в свой собственный коллекционный просмотр.

@protocol MyCollectionViewScrollProtocol <NSObject> 

- (void)scrolledToBottom; 

@end 

Затем в ViewController реализации данного протокола и в вашем CollectionView

создать слабый делегат свойство как это:

@property(weak, nonatomic) id<MyCollectionViewScrollProtocol> delegate; 

Тогда вы будете в состоянии назвать его

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{ 
    CGFloat offsetY = scrollView.contentOffset.y; 
    CGFloat contentHeight = scrollView.contentSize.height; 
    if (offsetY > contentHeight - scrollView.frame.size.height) 
    { 
     [self.delegate scrolledToBottom]; 
    } 
} 

и не забудьте установить свойство делегата из контроллера.


Редактируйте OP:

Контроллер должен содержать следующий код в .h файле:

#import <UIKit/UIKit.h> 

@protocol ViewControllerProtocol <NSObject> 
    - (void) Pong; 
@end 

@interface ViewController : UIViewController <ViewControllerProtocol> 

@end 

и следующий код где-то в .m файле:

#import "ViewController.h" 
@import UIKit; 
#import "myUnit.h" 

@interface ViewController() 
@end 

@implementation ViewController 


- (void)viewDidLoad { 
    [super viewDidLoad]; 
    myUnit mU = [[myUnit alloc] init]; 
    mU.linkToController = self; 
    [mU Ping]; 
} 

...... 

- (void) Pong{ 
    NSLog(@"Pong"); 
} 

...... 

блока, который хочет получить доступ к контроллеру необходимо иметь следующий код в файле .h:

#import <Foundation/Foundation.h> 
#import "ViewController.h" 

@interface myUnit : NSObject { 
} 

@property (weak, nonatomic) id <ViewControllerProtocol> linkToController; 

- (void)Ping; 

@end 

И блок, который хочет получить доступ к контроллеру необходимо иметь следующий код в файле .m:

#import "myUnit.h" 
#import "ViewController.h" 


@implementation myUnit 

- (void) Ping { 
    NSLog(@"Ping"); 
    [self.linkToController Pong]; 
} 


@end 
+0

Дод не видел этого ответа, когда я печатал мой :) Но это правильный способ сделать это :) – sloik

+0

Я нашел ответ благодаря вдохновению вашего ответа. Я написал ответ. – vaid

+0

@StanislavAgeev Кажется, что свойство delegate можно назвать чем-то другим, в моем случае я назвал его '@property (слабый, неатомный) id linkToController;'. Это приемлемый способ сделать это? Если «Да», то ваш ответ правильный, и мне удалось решить мою проблему, и я хотел бы отредактировать ваш ответ и добавить свой полный образец кода. – vaid

1

collectionView.parentView будет ViewController.view, который является полностью UIView, не имеет метода под названием onScrolledToBottom.

Вот такой подход, если я прав о том, чего вы хотите, но ЭТО ДЕЙСТВИТЕЛЬНО ДЕЙСТВИТЕЛЬНО ДЕЙСТВИТЕЛЬНО ПУТЬ.

в ViewController.m

....  

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view, typically from a nib. 
    [self initCollectionView]; 
} 
....  

- (void) getMoreInfo{ 
    NSLog(@"Getting more info"); 
}  

- (void) initCollectionView{ 
    UICollectionViewFlowLayout* flowLayout = [[UICollectionViewFlowLayout alloc]init]; 
    flowLayout.itemSize = CGSizeMake(50.0, 60.0); 
    flowLayout.sectionInset = UIEdgeInsetsMake(20, 0, 20, 0); 
    [flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical]; 
    flowLayout.headerReferenceSize = CGSizeMake(320.f, 30.f);  

    myCollectionView *mVC = [myCollectionView alloc] initWithParentViewController:self layout:flowLayout selector:@selector(getMoreInfo)]; 
} 

в myCollectionView.h

#import <UIKit/UIKit.h>  

@interface myCollectionView : UICollectionView<UIScrollViewDelegate, UICollectionViewDelegate, UICollectionViewDataSource>{ 
    UIViewController *_parentViewController; 
    SEL _onScrolledToBottom; 
}  

@property(weak) UIViewController *parentViewController; 
@property SEL onScrolledToBottom;  

- (id)initWithParentViewController:(UIView *)parentViewController layout:(UICollectionViewLayout *)layout selector:(SEL)onScrolledToBottomSEL; 
@end 

в myCollectionView.m

#import "myCollectionView.h"  

@implementation myCollectionView  

@synthesize parentViewController = _parentViewController; 
@synthesize onScrolledToBottom = _onScrollToBotton;  

- (id)initWithParentViewController:(UIView *)parentViewController layout:(UICollectionViewLayout *)layout selector:(SEL)onScrolledToBottomSEL{ 
    self = [super initWithFrame: CGRectMake(0.0f, 0.0f, parent.frame.size.width, parent.frame.size.height) collectionViewLayout: layout]; 
    if (self) { 
     _parentViewController = parentViewController; 
     self.delegate = self; 
     self.dataSource = self; 
     _onScrolledToBottom = onScrolledToBottomSEL; 
    }  
    return self; 
} 
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{ 
    CGFloat offsetY = scrollView.contentOffset.y; 
    CGFloat contentHeight = scrollView.contentSize.height; 
    if (offsetY > contentHeight - scrollView.frame.size.height) 
    { 
     [_parentViewController performSelector:@selector(onScrolledToBottom) withObject:nil]; 
    } 
} 

ВНИМАНИЕ:

  • В MVC не должно быть Controller, чтобы реализовать протокол, а не вид.
  • Первый символ имени класса должен быть капитализирован, вы должны использовать MyCollectionView вместо myCollectionView в качестве имени класса.
  • При использовании свойства компилятор LLVM автоматически генерирует переменную-член, не нужно декларировать ее снова.
  • В этом случае наилучшим способом является использование protocol-delegate.
+0

Спасибо. Я тоже подумал об этом, но могу ли я спросить, почему этот подход плох? – vaid

1

Ваш «myCollectionView» должен иметь делегата (вы должны создать протокол для этого) с каким-либо способом вдоль линии:

- (void)myCollectionViewDidScrollToBottom:(myCollectionView *)collectionView 

По представлению конвенции будет передан этот метод (как и любые методы делегата tableView). Затем в initCollectionView после myCollectionView *mVC = [myCollectionView alloc] init... вам придется установить этот делегат в текущий контроллер представления и реализовать этот метод.

mVC.delegate = self; 

... 
some other place in code 
... 

- (void)myCollectionViewDidScrollToBottom:(myCollectionView *)collectionView { 
    //do what's need to be done ;) 
} 

Теперь вашему «myCollectionView» все равно, где это и «кто». Любой, кто хотел бы использовать его, может реализовать этот метод и быть делегатом для этого представления с любой пользовательской логикой. То есть в этом методе вы бы назвали любые необходимые методы и любые другие вещи.

Как это работает:

  1. View, когда прокручивается вниз уведомляет это делегат об этом событии
  2. делегат обрабатывает всю логику, что нуждаются сделать

:)

0

Прежде всего хочу сказать спасибо всем вам.

Я прочитал все, что вы, ребята, написал, и я был вдохновлен.

Особенно ответ Станислава Агеев, где он сказал

Вы получаете SuperView вместо родительского контроллера ...

.

Я попытался передать контроллер как UIViewController вместо просмотра контроллера.

И я также удалил @selector() из scrollViewDidScroll и передал селектор напрямую.

EDIT Я пропустил ответ zy.lius. Кредит отправляется ему/ей для публикации ответа, который в основном объясняет, что я здесь сделал, хотя сам это понял. Сожалею.

Мой код теперь выглядит следующим образом (.h/.m):

Контроллер

.... 

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view, typically from a nib. 
    [self initCollectionView]; 
} 
.... 

- (void) getMoreInfo{ 
    NSLog(@"Getting more info"); 
} 

- (void) initCollectionView{ 
    UICollectionViewFlowLayout* flowLayout = [[UICollectionViewFlowLayout alloc]init]; 
    flowLayout.itemSize = CGSizeMake(50.0, 60.0); 
    flowLayout.sectionInset = UIEdgeInsetsMake(20, 0, 20, 0); 
    [flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical]; 
    flowLayout.headerReferenceSize = CGSizeMake(320.f, 30.f); 

    myCollectionView *mVC = [myCollectionView alloc] init: self: flowLayout: @selector(getMoreInfo)]; 
} 

myCollectionView.h файл:

#import <UIKit/UIKit.h> 

@interface myCollectionView : UICollectionView<UIScrollViewDelegate, UICollectionViewDelegate, UICollectionViewDataSource>{ 
    UICollectionView *parentController; 
    SEL onScrolledToBottom; 
} 

@property UICollectionView *parentController; 
@property SEL onScrolledToBottom; 

- (id)init: (UICollectionView*) parent: (UICollectionViewLayout *)layout: (SEL)onScrolledToBottomSEL; 
@end 

и файл .m:

#import "myCollectionView.h" 

@implementation myCollectionView 

@synthesize parentController = parentController; 
@synthesize onScrolledToBottom = onScrollToBotton; 

- (id)init: (UIView*) parent: (UICollectionViewLayout *)layout: (SEL)onScrolledToBottomSEL{ 
    self = [super initWithFrame: CGRectMake(0.0f, 0.0f, parent.view.frame.size.width, parent.view.frame.size.height) collectionViewLayout: layout]; 
    if (self) { 
     parentController = parent; 
     self.delegate = self; 
     self.dataSource = self; 
     onScrolledToBottom = onScrolledToBottomSEL; 
    } 

    return self; 
} 
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{ 
    CGFloat offsetY = scrollView.contentOffset.y; 
    CGFloat contentHeight = scrollView.contentSize.height; 
    if (offsetY > contentHeight - scrollView.frame.size.height) 
    { 
     [parentController performSelector:@onScrolledToBottom withObject:nil]; 
    } 
} 

Эта работа отлично, и это можно использовать для связи с основным контроллером по-разному.

И это очень просто.

Еще раз спасибо за то, что вдохновили меня найти наиболее эффективное решение.

+0

Ну, этот ответ неверен несколькими способами. Прежде всего, у вас есть утечка памяти, так как после введения атрибута неявного атрибута ARC сильно, так что вы в основном создаете замкнутый цикл между представлением и контроллером. Во-вторых, ответ имеет множество опечаток, которые делают его неправильным. И, в-третьих, вам следует рассмотреть возможность использования протокола, поскольку он уменьшит количество ошибок и аннотирует контроллер, как он должен быть (дети не должны иметь явные сведения об их родителях). –

+0

@StanislavAgeev вы могли бы связать документ по протоколу? Мне может понадобиться просветить себя, чтобы я мог правильно его реализовать. – vaid

+0

проверить эту ссылку https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithProtocols/WorkingwithProtocols.html и посмотреть на мой ответ , Это позволит решить как утечку памяти, так и недостающий уровень абстракции. –

Смежные вопросы