在superView上执行选择器

时间:2015-08-17 14:56:54

标签: ios objective-c uiscrollview selector

我有UICollectionView使用- (void)scrollViewDidScroll:(UIScrollView *)scrollView来确定用户何时滚动到底部。

我的UICollectionView的所有者有一个方法可以向服务器发送命令并要求提供更多数据。

我想要做的是从我的UICollectionView,特别是scrollViewDidScroll内的所有者(我的viewcontroller)执行选择器。

我尝试使用以下代码执行此操作:

- (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];
    }
} 

注意:选择器onScrolledToBottomSEL的{​​{1}}属性。

我得到的错误说:

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'

中有关注
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

4 个答案:

答案 0 :(得分: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

答案 1 :(得分: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是最好的方式。

答案 2 :(得分:1)

你的&#34; myCollectionView&#34;应该有一个委托(你将不得不为此创建一个协议),并采用一些方法:

- (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 ;)
}

现在你的&#34; myCollectionView&#34;并不关心它在哪里,而是由#34;谁&#34;。任何想要使用它的人都可以使用任何自定义逻辑实现此方法并成为该视图的委托。这就是在这种方法中你可以调用任何必需的方法和任何其他东西。

这是如何运作的:

  1. 向下滚动时查看通知其代表此事件
  2. 代表处理所有需要完成的逻辑
  3. :)

答案 3 :(得分:0)

首先,我想对所有人说声谢谢。

我读完了你们写的所有内容,我受到启发。

特别是Stanislav Ageev的答案,他说

  

你得到的是superview而不是父控制器......

我试图将控制器本身作为UIViewController而不是控制器的视图传递。

我还从@selector()中移除了scrollViewDidScroll并直接传递了选择器。

编辑我错过了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];
    }
}

这非常好用,可用于以各种方式与主控制器通信。

这很简单。

再次感谢鼓励我找到最有效的解决方案。