-setNeedsDisplay 没有被调用来刷新 drawRect

Posted

技术标签:

【中文标题】-setNeedsDisplay 没有被调用来刷新 drawRect【英文标题】:-setNeedsDisplay not getting called to refresh drawRect 【发布时间】:2012-06-26 23:21:11 【问题描述】:

我有两个从 -drawRect: 内部调用的方法

- (void)drawRect:(CGRect)rect  

    if(drawScheduleFlag) 
        [self drawSchedule];
        drawScheduleFlag = false;
    
    else
        [self drawGrid];

-drawGrid 在初始化时被调用。另一个方法(-drawSchedule)是从这段代码中调用的,它在主线程上:

- (void) calendarTouched: (CFGregorianDate) selectedDate  

//    NSLog(@"calendarTouched - currentSelectDate: %d/%d/%d", selectedDate.month, selectedDate.day, selectedDate.year);
//    NSLog(@"Main thread? %d", [NSThread isMainThread]);

    //  get data from d/b for this date (date, staff name, cust name, time, length, services required)
    //------    stub    -------
    scheduledDate.year = 2012;
    scheduledDate.month = 6;
    scheduledDate.day = 20;
    staffName = @"Saori";
    custName = @"Brian";
    startTime.hour = 11;
    duration = 2;
    servicesReqd = @"Nails";

    drawScheduleFlag = true;
    [self setNeedsDisplay];

    return;

我知道代码正在执行,但绘制时间表没有任何反应。为什么-[self setNeedsDisplay] 没有导致-drawRect 被调用?

更新:我已经插入了中断,所以我很肯定它没有被调用。原网格绘制一次;当用户点击日历日期时,会调用 -calendarTouched 并完全执行。 drawScheduleFlag 设置为 true,并且 -[self setNeedsDisplay] 被调用,但 -drawRect 没有。似乎 UIView 没有失效(应该是 -setNeedsDisplay ),因此 -drawRect 没有被调用。

更新 #2:我有一个用于 UIViewController 的 .xib,其中包含两 (2) 个 UIView。第一个 UIView 占据 iPad 屏幕的 1/3 左右,第二个 UIView 占据屏幕底部的 2/3。每个 UIView 都有自己的特定类;顶部的 UIView 显示日历并且工作正常,捕捉触摸并更改所选日期。

底部的 UIView 应该显示顶部 UIView 中选择的日期的时间表。这就是问题所在。由于顶部 UIView 正在工作,我将放置底部 UIView 类的代码。它基本上在第一次调用 -drawRect 时绘制计划网格。一旦用户选择了一天,它应该使 UIView 无效以在网格上绘制实际的时间表。

这是 Schedule.h 的代码:http://pastebin.com/NQpj0i07 这是 Schedule.m 的代码:http://pastebin.com/YBbE8y0T 这是控制器的代码:http://pastebin.com/nDqBCivj 请注意,从太平洋标准时间 6 月 28 日下午 5:38 起,两个 pastebin 都将在 24 小时内到期

【问题讨论】:

你确定它没有被调用吗?你确定它只被调用一次吗?设置断点。可能是被调用了,但是之后直接又被调用了,然后到drawGrid,估计又把schedule删掉了。 “-drawGrid 在初始化时被调用”这句话听起来很恶心...... 我认为您需要提供更多代码和上下文。另外,此时您的视图是否存在于视图层次结构中? 调用-setNeedsDisplay:的代码是在主线程上吗?如果没有,那就是你的问题。 嗨,Richard... 是的,它在主线程上(使用 -NSLog(@"Main thread? %d", [NSThread isMainThread]); 返回 1) 【参考方案1】:

重复我在 cmets 中所说的话,您遇到的问题是您的 UIView 子类对象在执行 drawRect 调用之前被释放,这意味着任何持有对该对象的引用,在此如果您的控制器在您打算之前发布它,有时会出现使用 ARC 的小问题。

在包含此视图的控制器代码中,您应该声明如下内容:

@property (weak, nonatomic) IBOutlet Schedule *scheduleView;

并合成:

@synthesize scheduleView = _scheduleView;

并且在控制器的dealloc方法中:

self.scheduleView = nil;

如果您使用的是故事板,但您似乎没有使用它,因为您为此制作了一个 .xib 文件,您应该正确连接它。如果不是简单地实例化它并分配它。

扩展我之前所说的内容,我不确定您要做什么,但看看您的代码,当通知被调用时,您正在创建视图的短暂时刻,并且在那里它被释放,因为没有人提到它。通过按照我所说的操作并单击从控制器拖动到界面构建器中的视图并将其连接起来,它将保留对它的引用,并且您只会创建 1 个 Schedule 对象。

之后,您必须修改代码以使用此 Schedule 实例:

- (void) testNotification:(NSNotification *) notification  

    //  was the calendar tapped?
    if ([[notification name] isEqualToString:@"calendarUpdated"])  

        NSDictionary *passedData = notification.userInfo;  //  get passed data
        CFGregorianDate currentSelectDate;
        NSData *data = [passedData objectForKey:@"currentSelectDate"];
        [data getBytes:&currentSelectDate length:sizeof(CFGregorianDate)];

        [self.scheduleView calendarTouched:currentSelectDate];
    

    return;


如果您不使用界面生成器来设置所有内容,则可以在 viewDidLoad 中使用以下选项:

- (void)viewDidLoad

    [super viewDidLoad];

    self.scheduleView = [[Schedule alloc] init];
    [self.view addSubView:self.scheduleView]; // Probably some extra code for positioning it where you want

    // notify me when calendar has been tapped and CFGregorianDate has been updated
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(testNotification:) name:@"calendarUpdated" object:nil ];


最后一点,考虑到您是 ios 开发新手(就像我们一样),您可以前往 iTunes 并在 iTunes U 上查找斯坦福大学的 iPad 和 iPhone 开发课程 (CS193P),它是完全免费的,而且会教在 iOS 中进行开发需要了解的大部分内容。

【讨论】:

没有任何声明...这可能是问题所在,是吗?这里是控制器的代码:pastebin.com/nDqBCivj 这里是 CalendarView.h 的代码,它是上层 UIView 的类。我看到它有你所指的;我必须对 Schedule.h 做类似的事情吗? 是的,很可能,你没有任何东西可以引用你的观点,所以它只是内存不足,按照我在答案中所说的方式声明它,让我知道它是怎么回事.请记住要么在 Interface Builder 中连接它,要么在控制器中实例化它并分配它 参见我上面的帖子,参考 CalendarView.h。我明天会这样做,因为该吃饭了。我很感激你的时间。在太平洋时间早上 7 点之后查找我的帖子...再次感谢... 没问题,希望真的是这样,它可以解决您的问题 :) 看到您实例化 Schedule 视图的行,它开始存在,然后在那里被取消引用,像我一样持有指向它的指针当你实例化你的控制器时说,或者创建,持有对它的引用,然后调用它的方法,因为对于每个通知,你都在创建一个新的 Schedule 对象。 我不想要求太多......但你能指点我一个文档,它解释了如何创建指针并保持它吗? (我在这么深的 Objective-c 方面相对较新,有点困惑)。

以上是关于-setNeedsDisplay 没有被调用来刷新 drawRect的主要内容,如果未能解决你的问题,请参考以下文章

使用 Ajax 调用刷新 JSP 页面上的 div 而没有响应

需要调用两次 setter 来强制在 MFC 中刷新 GUI

Node.js 集群共享缓存

具有后台刷新功能的 APN。当 APN 被传递和通知被点击时,刷新调用了两次? [复制]

我是不是使用刷新令牌?

使用 UIRefreshControl 刷新 UITableView