EAGLView到UIImage的计时问题 [英] EAGLView to UIImage timing question

查看:98
本文介绍了EAGLView到UIImage的计时问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个EAGLView,希望将其转换为UIImage.我可以使用此处发布的解决方案来做到这一点:

如何从EAGLView获取UIImage?

但是,只有在创建EAGLView和UIImage之间花费了少量时间的情况下,我才能完成此操作.

此代码(先创建EAGLView,然后再创建UIImageView)不起作用:

EAGLView *EAGLphoto = [[EAGLView alloc] initWithImage:photo.workAreaImage];

[theWorkArea.photoArea1 addSubview:EAGLphoto];

//I put a glfinish() here but it didn't help

UIImageView *photoView = [[UIImageView alloc] initWithImage:[self glToUIImage]];
//glToUIImage is taken from the link above

[theWorkArea.photoArea2 addSubview:photoView];

我假设在创建EAGLView之前尝试创建UIImageView.我试图在两者之间放一个glfinish(),但是它什么也没做.当我运行代码时,EAGLView可以正常显示,但UIImageView可以显示为黑色.

但是,上述代码的修改后版本有效:

EAGLView *EAGLphoto = [[EAGLView alloc] initWithImage:photo.workAreaImage];

[theWorkArea.photoArea1 addSubview:EAGLphoto];

[self performSelector:@selector(getUIImage) withObject:nil afterDelay:0.1];

- (void)getUIImage {

    UIImageView *photoView = [[UIImageView alloc] initWithImage:[self glToUIImage]];
    //glToUIImage is taken from the link above

    [theWorkArea.photoArea2 addSubview:photoView];

}

我使用glfinish()的方式不正确吗?有没有比我的黑客更好的方法?

解决方案

通常,当您对UIKit对象进行可见更改而不是立即更新时,它们只是将自己标记为将来进行更改,然后将整个更改集标记为下次您放弃主线程(返回到运行循环)时进行批处理.这不是功能失常或实现失败,实际上通常是您隐含的期望,这是您可以编写以下代码的原因:

view.frame = someNewFrame;
view.someOtherProperty = someOtherValue;

不必担心视图经常会在采用其他更改之前明显采用新框架.通常,您希望对视图执行的操作看起来像是原子的.

有时您会遇到一种情况,就像您在这里遇到的那样,这种情况已经暴露出您已经请求的更改尚未生效的事实.在上面的示例中,framesomeOtherProperty将返回其新值,因此您不必担心更改是否立即生效,但是基于对performSelector:withObject:afterDelay:的观察,您似乎偶然发现了这种变化并非假装是立即发生的.

EAGLView很难诊断,因为它实际上不是UIKit功能.它是基于CAEAGLLayer的,但是EAGLView只是Apple在各种示例项目中为基于CAEAGLLayer构建的自定义UIView子类所采用的名称.他们在示例中关于EAGLView的接口或实现并不一致,但是我猜想我可能是在创建OpenGL帧缓冲区对象(即OpenGL用于存储与以下内容有关的数字的对象)像素,允许glReadPixels起作用)仅在被要求布局时才出现,并且直到UIKit要求布局时才布局.直到您退出运行循环为止.

可以通过检查您拥有的EAGLView的代码来确认该诊断.如果由于layoutSubviewsdrawRect或相关init未直接调用的其他方法而触发了诸如glGenFramebuffers之类的大量调用,那么就证明了这一点.

假设诊断正确,则可以采用EAGLView,但我认为最好的解决方案是坚持使用performSelector:withObject:afterDelay:0.这不是争用条件,因此解决方案并非一帆风顺或不可靠,它只是说让UIKit赶上所有这些指令,因为我知道可以让EAGLView来"只是一种a回曲折的方式.进入有意义的状态,然后继续我的东西".

I have a EAGLView that I wish to convert into a UIImage. I can do this with the solution posted here:

How to get UIImage from EAGLView?

However, I can only accomplish this if a small amount of time has gone by between the creation of the EAGLView and the UIImage.

This code, which creates a EAGLView, and then a UIImageView right afterwards, does not work:

EAGLView *EAGLphoto = [[EAGLView alloc] initWithImage:photo.workAreaImage];

[theWorkArea.photoArea1 addSubview:EAGLphoto];

//I put a glfinish() here but it didn't help

UIImageView *photoView = [[UIImageView alloc] initWithImage:[self glToUIImage]];
//glToUIImage is taken from the link above

[theWorkArea.photoArea2 addSubview:photoView];

I'm assuming the UIImageView tries to get created before the EAGLView is finished being created. I tried to put a glfinish() in between but it did nothing. When I run the code, the EAGLView shows up fine but the UIImageView shows up as black.

However, this modified version of the above code works:

EAGLView *EAGLphoto = [[EAGLView alloc] initWithImage:photo.workAreaImage];

[theWorkArea.photoArea1 addSubview:EAGLphoto];

[self performSelector:@selector(getUIImage) withObject:nil afterDelay:0.1];

- (void)getUIImage {

    UIImageView *photoView = [[UIImageView alloc] initWithImage:[self glToUIImage]];
    //glToUIImage is taken from the link above

    [theWorkArea.photoArea2 addSubview:photoView];

}

Am I using glfinish() incorrectly? Is there a better method than my hack?

解决方案

Usually when you make visible changes to UIKit objects instead of updating instantly they merely flag themselves to make those changes in the future, then do the whole set of changes as a batch next time you relinquish the main thread (by returning to the runloop). That's not a misfeature or a failure in the implementation, it's actually usually what you implicitly expect, being the reason you can write code like:

view.frame = someNewFrame;
view.someOtherProperty = someOtherValue;

And not worry that every so often the view will visibly adopt the new frame before adopting the other changes. As a rule, you want the things you do to views to appear to be atomic.

Occasionally you run into a situation, as you have here, where the fact that changes you've already requested haven't come into effect yet is exposed. frame and someOtherProperty would return their new values in the above example so that you don't care whether the changes took effect immediately or not, but based on your observation about performSelector:withObject:afterDelay: it seems likely that you've stumbled upon a situation where the change doesn't pretend to be immediate.

EAGLView is difficult to diagnose because it's not really a UIKit feature. The CAEAGLLayer that it's built upon is, but EAGLView is just the name Apple have adopted for a custom UIView subclass built on CAEAGLLayer in various example projects. They've not been consistent about the interface or implementation of EAGLView across their examples, but at a guess I'd say that probably it's creating the OpenGL frame buffer object (that is, the thing that OpenGL uses to store numbers related to pixels, allowing glReadPixels to work) only when asked to lay itself out, and it doesn't lay itself out until UIKit asks it to do so. Which isn't until you've dropped out to the runloop.

That diagnosis can be confirmed by checking the code of the EAGLView that you have. If there are a bunch of calls to things like glGenFramebuffers that are triggered as a result of layoutSubviews, drawRect or some other method that isn't called directly by the relevant init then that proves it.

Assuming that diagnosis to be correct, you could adapt EAGLView but I think probably the best solution is just to stick to performSelector:withObject:afterDelay:0. This isn't a race condition, so that solution isn't in the slightest bit flakey or unreliable, it's just a slightly roundabout way of saying "let UIKit catch up with all of those instructions, given that I know that'll let EAGLView get into a meaningful state, then continue with my stuff".

这篇关于EAGLView到UIImage的计时问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆