【问题标题】:UIView is not responding when changed in NSTimer method在 NSTimer 方法中更改时 UIView 没有响应
【发布时间】:2015-05-25 09:23:20
【问题描述】:

我有这个 NSTimer 重复循环,它将检查我的应用程序中是否有任何新闻。检查部分无关紧要,它工作正常,但为了显示是否有新闻,我制作了一个名为 orangeDot 的 UIView。如果有新闻,应该是orangeDot.alpha = 1.0,如果没有,应该是orangeDot orangeDot.alpha = 0.0。但它并不总是有效。有时,当有新闻时,orangeDot 会被隐藏(alpha=0),有时则相反。这是代码:

-(void) checkForNews {
    NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
    bool news = (([defaults boolForKey:@"newsFromChat"]) || ([defaults boolForKey:@"newsFromAwaiting"])) ? YES : NO;

    if (news) {
        NSLog(@"yay news");
        [orangeDot setAlpha:1.0f];
    } else {
        NSLog(@"nothing new");
        [orangeDot setAlpha:0.0f];
    }

    NSLog(@"%@",orangeDot);
}

NSLog 工作完美,这部分从来没有问题,但即使日志显示“yay news”,orangeDot 也可能被隐藏,反之亦然。但有时它会起作用......我还没有在错误中找到模式。 我不得不提到 .alpha 和 .hidden 都不能正常工作。

orangeDot 是这样坐起来的:

@property (nonatomic, retain) IBOutlet UIView * orangeDot;

并在故事板中连接。

请帮忙:)

【问题讨论】:

  • 贴出计时器的周围代码。
  • NSLog 做得很完美,所以它以某种方式连接到接口。 NSLog(@"%@",orangeDot);还应该将 orangeDot 打印为 fx alpha=1.0,但它实际上隐藏在界面中。
  • 可能定时器触发的代码没有在主(UI)线程上执行。我建议您将 orangeDot 方法调用作为一个块发布到主队列。
  • 正是@RudiAngela 所说的,这就是为什么我希望你发布周围的代码。可以dispatch_async(dispatch_get_main_queue(), ^{//wrap contents of -checkForNews in here}使用主线程。

标签: objective-c xcode uiview alpha iboutlet


【解决方案1】:

根据您的代码,我想到了两件事:

  1. UIView 更新应该在主线程上进行。检查你是从主线程调用这个方法,还是从主线程调用这个方法。

    - (void)checkForNews {
    
        dispatch_async(dispatch_get_main_queue(), ^{
    
            NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
            bool news = (([defaults boolForKey:@"newsFromChat"]) || ([defaults boolForKey:@"newsFromAwaiting"])) ? YES : NO;
    
            if (news) {
                NSLog(@"yay news");
                [orangeDot setAlpha:1.0f];
            } else {
                NSLog(@"nothing new");
                [orangeDot setAlpha:0.0f];
            }
    
            NSLog(@"%@",orangeDot);
        });
    }
    
  2. 您的orangeDot 声明似乎有点可疑。您是否声明了其他具有相同名称的变量?尝试拨打self.orangeDot 而不是只拨打orangeDot。通常 Xcode 不会让我们以您的方式访问 IBOutlet。如果您声明一次且正确,您将能够通过self.orangeDot 或仅通过_orangeDot(带有初始下划线字符)访问该对象。

    //using .self
    [self.orangeDot setAlpha:1.0f];
    
    //or using underline to access the var. without setter
    [_orangeDot setAlpha:1.0f];
    

更新:

您真的需要循环检查用户默认设置的更新吗?忘记这个计时器的东西并实现 NSNotification 模式(或委托,或其他)怎么样?你只需要发送一个通知事件并在你的相对视图控制器上监听它:我希望你已经知道如何实现它,但我会在这里留下一个小例子:

//Somewhere ... just after you update your news data.
[[NSNotificationCenter defaultCenter] postNotificationName:@"NewChatDataAvailable" object:nil];

此时,您是在告诉整个应用您有新的聊天数据可用,而无需进行不必要的循环检查。现在我们需要做的就是注册以接收此通知:

//In this example I will register on viewDidLoad:

- (void)viewDidLoad:(BOOL)animated {

    [super viewDidLoad:animated];

    //Now, your method will be called on when necessary (when data arrives)
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(checkForNews)
                                                 name:@"NewChatDataAvailable"
                                               object:nil];
}

现在,让我们稍微改进一下您的代码:

- (void)checkForNews {

    dispatch_async(dispatch_get_main_queue(), ^{

        NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];

        //You don't need to put the ? YES : NO stuff, and BOOL in capital letters
        BOOL hasNews = (([defaults boolForKey:@"newsFromChat"]) ||
                         ([defaults boolForKey:@"newsFromAwaiting"]));

        if (hasNews) {
            NSLog(@"yay news");
            [self.orangeDot setAlpha:1.0f];
        } else {
            NSLog(@"nothing new");
            [self.orangeDot setAlpha:0.0f];
        }

        NSLog(@"%@",self.orangeDot);
    });
}

希望对你有帮助。而且...当您使用代码或其他内容更新您的问题时,请编辑您的问题并将代码插入其中,不要将其作为答案发布。

【讨论】:

  • 你甚至可以写self.orangeDot.alpha = 1。无需使用 1.0f,因为数字文字被推断为 alpha 的任何类型。
  • dispatch_async(dispatch_get_main_queue(), ^{ });没有改变任何东西。它仍然没有正确响应。
  • 是的,橙色点在文件中是@synthesize'd。
  • 所以你必须发布更多关于你的代码......顺便说一句,你为什么使用@synthesize?我们不再需要隐式使用它了...
  • @Schemetrical > 使用 1.0f 是一种很好的做法,有时编译器无法正确转换它。
【解决方案2】:

感谢您到目前为止的帮助!

更好地了解代码:

...
@synthesize orangeDot; 
... 

- (void) viewDidLoad {
   ...
   [self reloader];
   ...
}

- (void) reloader{
    if (refreshAuto == nil) {
    refreshAuto = [NSTimer scheduledTimerWithTimeInterval: 2.0
                      target: self selector:@selector(checkForNews) userInfo: nil repeats:YES];
    }    
}

 - (void)checkForNews {
    dispatch_async(dispatch_get_main_queue(), ^{
    NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
    bool news = (([defaults boolForKey:@"newsFromChat"]) || ([defaults boolForKey:@"newsFromAwaiting"])) ? YES : NO;

    if (news) {
        NSLog(@"yay news");
        [orangeDot setAlpha:1.0f];
    } else {
        NSLog(@"nothing new");
        [orangeDot setAlpha:0.0f];
    }

    NSLog(@"%@",orangeDot);
    });
}

当显示 orangeDot 时,日志有时会如下所示:

...
2015-05-25 12:02:23.788 Teazr[1314:442396] nothing new
2015-05-25 12:02:23.789 Teazr[1314:442396] <UIButton: 0x154520f40; frame = (322 47; 11 11); alpha = 0; opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x17422a740>>
...

@synthesizing 是个人喜好,不是必需的。但它与 self.orangeDot 的工作方式相同,并且没有合成..

【讨论】:

  • 请检查您的数据类型:BOOLbool 不同,请将您的 bool news 更改为 BOOL news BOOL - YES/NO 和 bool - true/false。尝试更改它..有时会导致这样的问题..因为您使用的是YES : NO而不是true : false
  • 嗯,但布尔工作正常。它总是在循环中记录来自 NSLog 的正确“答案”..
  • 这个orangeDot到底在哪里?在一张桌子上?
  • 不,它只是放在 UIViewController 中的主 UIView 上。当我将其放置为 [self.view addSubview:orangeDot]; 时,我得到了相同的结果。 .. :(
  • 试着把这个- (void)viewWillLayoutSubviews { [super viewWillLayoutSubviews]; } 哈哈..我也想不通它是怎么回事看起来对我来说功能齐全..哈哈哈..我稍后再试试,让你知道我有什么找到.. :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-16
  • 1970-01-01
  • 1970-01-01
  • 2018-10-09
相关资源
最近更新 更多