rxjava框架: http://gank.io/post/560e15be2dca930e00da1083
分类: 未分类
Xcode 编译静态库的陷阱(Xcode7如何生成i386的静态库)
Unicode详细解释
http://objccn.io/issue-9-1/
ES3.0 中 Vertex Shader 的out变量未赋值,导致 glLinkProgram 失败
这其实是我在群里问这位大神的问题,当时是获取不到 glGetUniformLocation(program, “s_texture”); 这个东西。
版权声明:本文转自http://blog.csdn.net/huutu 转载请带上 http://www.thisisgame.com.cn
GLSL中,定义了但是 没有使用的变量会被优化掉,在之前就遇到过。
(GLSL 中 ,如果定义的 变量 没有在代码中使用到,那么不会被编译,用 glget* 是获取不到的,返回 -1 。算是被优化掉了。
http://blog.csdn.net/huutu/article/details/50322905 )
而且如果 Vertexshader 中的定义的 Out 变量未使用,被优化掉后,会引起 FragmentShader 的问题,导致 glLinkProgram 失败!
群里朋友 学习 ES3.0的时候 碰到一个问题:
编译下面的Shader 并没有出错,但是使用
- glGetUniformLocation(program, “s_texture”);
去获取 的时候,却返回了 -1 。转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn
Vertex Shader:
- #version 300 es
- precision mediump float;
- in vec3 inPos;
- in vec2 vTexCoord;
- out vec3 Color;
- out vec2 texCoord;
- uniform mat4 myMat;
- void main() {
- gl_Position = vec4(inPos, 1.0) * myMat;
- Color = inPos;
- }
Fragment Shader:
- #version 300 es
- precision mediump float;
- in vec3 Color;
- in vec2 texCoord;
- out vec4 fragmentColor;
- uniform sampler2D s_texture;
- void main() {
- fragmentColor = texture(s_texture, texCoord);
- }
我的第一反应是:
s_texture 没有使用,被优化掉了。
然而并没有,让朋友把工程传过来看了一段时间才发现
在Vertex Shader 中的 out vec2 texCoord; 没有赋值!!
所以 texCoord 是被优化掉了的。
但是 在 FragmentShader 中的 in vec2 texCoord 是存在的变量,所以呢 glCompileShader 操作的时候是不会报错的!
转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn
难道 OpenGL 没有处理这个问题?当然不是。
这个错误是在 glLinkProgram 阶段抛出的。 朋友没有去获取 glLinkProgram 的状态,所以没有发现这个错误。
抛出了很详细的错误
- WARNING: Output of vertex shader ‘Color’ not read by fragment shader
- ERROR: Input of fragment shader ‘texCoord’ not written by vertex shader
- (lldb)
IOS开发中遇到转发delegate的时候不要再那么傻了
http://sam.dods.co/blog/2014/08/03/secondary-delegate/
delegate代理(截取delegate消息用)
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @interface MovieSDKDelegateProxy : NSObject <UITableViewDelegate> @property (nonatomic, weak)id primaryDelegate; @property (nonatomic, weak)id secondaryDelegate; @end
@implementation MovieSDKDelegateProxy - (BOOL)respondsToSelector:(SEL)aSelector { return ([self.primaryDelegate respondsToSelector:aSelector] || [self.secondaryDelegate respondsToSelector:aSelector]); } - (NSMethodSignature *)methodSignatureForSelector:(SEL)selector { NSObject *delegateForResonse = [self.primaryDelegate respondsToSelector:selector] ? self.primaryDelegate : self.secondaryDelegate; return [delegateForResonse respondsToSelector:selector] ? [delegateForResonse methodSignatureForSelector:selector] : nil; } - (void)forwardInvocation:(NSInvocation *)invocation { [self invokeInvocation:invocation onDelegate:self.primaryDelegate]; [self invokeInvocation:invocation onDelegate:self.secondaryDelegate]; } - (void)invokeInvocation:(NSInvocation *)invocation onDelegate:(id)delegate { if ([delegate respondsToSelector:invocation.selector]) { [invocation invokeWithTarget:delegate]; } } @end
use:注意设置每个delegate时必须重新将_proxy设置给tableView的delegate。这样才能保证tableView重新检查delegate支持的方法。(tableView会在设置delegate时将大多数方法都检查一下是否支持,回调时不再检查)
@implementation MovieSDKRefreshTableView { MovieSDKDelegateProxy *_proxy; } - (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style { self = [super initWithFrame:frame style:style]; if (self) { _proxy = [MovieSDKDelegateProxy new]; _proxy.primaryDelegate = self; [super setDelegate:self]; } return self; } - (id<UITableViewDelegate>)delegate { return _proxy.secondaryDelegate; } - (void)setDelegate:(id<UITableViewDelegate>)delegate { _proxy.secondaryDelegate = delegate; [super setDelegate:nil]; //Important:must reset delegate, because tableView check all response to @selecter when set delegate [super setDelegate:_proxy]; } @end
C++仿GCD多线程用法
typedef std::function<void(void)> MyFun; typedef enum XTaskPriority { XTaskPriority_High, XTaskPriority_Default, XTaskPriority_Low, XTaskPriority_Background, }XTaskPriority; class XThreadPool; class XTaskQueue { std::mutex mutex; std::queue<MyFun> queue; public: XThreadPool *runInPool; static std::shared_ptr<XTaskQueue> getMainQueue() { //TODO::maybe mutithread cause problem static std::shared_ptr<XTaskQueue> mainQueue(new XTaskQueue()); return mainQueue; } static std::shared_ptr<XTaskQueue> getGlobleQueue(XTaskPriority priority) { static std::shared_ptr<XTaskQueue> backgroundQueue(new XTaskQueue()); static std::shared_ptr<XTaskQueue> lowQueue(new XTaskQueue()); static std::shared_ptr<XTaskQueue> defaultQueue(new XTaskQueue()); static std::shared_ptr<XTaskQueue> highQueue(new XTaskQueue()); switch (priority) { case XTaskPriority_Background: return backgroundQueue; case XTaskPriority_Low: return lowQueue; case XTaskPriority_High: return highQueue; case XTaskPriority_Default: default: return defaultQueue; } } bool pop(MyFun &fun) { std::unique_lock<std::mutex> lk(mutex); if(queue.size() > 0) { fun = std::move(queue.back()); queue.pop(); return true; } return false; } void push(const MyFun &fun) { mutex.lock(); queue.push(fun); mutex.unlock(); } }; class XThreadPool { private: std::atomic_int_fast8_t threadNum; int_fast8_t maxNum; std::atomic_int taskNum; std::mutex mutex; std::condition_variable cv; void runLoop() { ++threadNum; do { std::unique_lock<std::mutex> lk(mutex); auto iter = taskQueue.begin(); auto end = taskQueue.end(); MyFun fun; bool hasFun = false; while (iter != end) { if((*iter)->pop(fun)) { hasFun = true; break; } ++iter; } if (hasFun) { lk.unlock(); fun(); } else { cv.wait(lk); } } while (1); --threadNum; } public: std::vector<std::shared_ptr<XTaskQueue>> taskQueue; void onQueueChanged() { mutex.lock(); cv.notify_one(); mutex.unlock(); } //初始化两个全局Pool static void initGlobelPool() { static XThreadPool mainThread; mainThread.taskQueue.push_back(XTaskQueue::getMainQueue()); XTaskQueue::getMainQueue()->runInPool = &mainThread; mainThread.startNewThread(); static XThreadPool backgroundThreadsPool; backgroundThreadsPool.taskQueue.push_back(XTaskQueue::getGlobleQueue(XTaskPriority_High)); backgroundThreadsPool.taskQueue.push_back(XTaskQueue::getGlobleQueue(XTaskPriority_Default)); backgroundThreadsPool.taskQueue.push_back(XTaskQueue::getGlobleQueue(XTaskPriority_Low)); backgroundThreadsPool.taskQueue.push_back(XTaskQueue::getGlobleQueue(XTaskPriority_Background)); XTaskQueue::getGlobleQueue(XTaskPriority_Background)->runInPool = &backgroundThreadsPool; XTaskQueue::getGlobleQueue(XTaskPriority_Low)->runInPool = &backgroundThreadsPool; XTaskQueue::getGlobleQueue(XTaskPriority_Default)->runInPool = &backgroundThreadsPool; XTaskQueue::getGlobleQueue(XTaskPriority_High)->runInPool = &backgroundThreadsPool; for (int i = 0; i < 4; ++i) { backgroundThreadsPool.startNewThread(); } } void startNewThread() { std::thread thread(std::bind(&XThreadPool::runLoop, this)); thread.detach(); } XThreadPool() { taskNum = 0; } virtual ~XThreadPool() { } }; struct XTask { public: std::function<void(void)> fun; std::shared_ptr<XTaskQueue> queue; std::chrono::time_point<std::chrono::system_clock> time; bool operator <(const XTask& rh) { return time < rh.time; } }; class XDispatchManager { private: std::mutex mutex; std::condition_variable cv; std::vector<XTask> mQueue; void runLoop() { do { std::unique_lock<std::mutex> lk(mutex); if (mQueue.empty()) { cv.wait(lk); } else { cv.wait_until(lk, mQueue.begin()->time); auto now = std::chrono::system_clock::now(); if (now >= mQueue.begin()->time) { auto taskQueue = mQueue.begin()->queue; taskQueue->push(mQueue.begin()->fun); if (taskQueue->runInPool) { taskQueue->runInPool->onQueueChanged(); } mQueue.erase(mQueue.begin()); } } } while (1); } public: static XDispatchManager* getSharedInstance() { static XDispatchManager *manager = new XDispatchManager(); return manager; } XDispatchManager() { XThreadPool *pool = new XThreadPool(); std::thread thread(std::bind(&XDispatchManager::runLoop, this)); thread.detach(); } inline void dispatchAsnyc(std::shared_ptr<XTaskQueue> taskQueue, const MyFun &fun) { taskQueue->push(fun); if(taskQueue->runInPool) { taskQueue->runInPool->onQueueChanged(); } } void dispatchAfter(std::shared_ptr<XTaskQueue> taskQueue, const MyFun &fun, long delayMS) { XTask task; task.fun = fun; task.queue = taskQueue; task.time = std::chrono::system_clock::now() + std::chrono::milliseconds(delayMS); mutex.lock(); mQueue.insert(std::upper_bound(mQueue.begin(), mQueue.end(), task, [](const XTask &lh, XTask &rh)->bool { return lh.time < rh.time; }), task); mutex.unlock(); cv.notify_one(); } };
std::function详细用法示例
原文: http://www.jellythink.com/archives/771
不允许转载 先这样空着吧~
IOS KeyChain存储结构详解
先推荐一个链接:WHJ的一篇博文,最后一句话实际上很重要,我们下边也会提及。
苹果文档叫做:Keychain Services Reference
KeyChain可以用来储存加密的数据,或者相同TeamID应用间共享数据。并且卸载应用后不会被清除。
KeyChain的实现就相当于储存一个个的Dictionary(官方叫它SecItem),不过里边的key要按照系统规定方式设置。其中有几个重要的key(稍后会详细列出)。并且key有三个类型:标示整体类型的key(只有一个:kSecClass)、设置详细属性的key(kSecAttrGeneric、kSecAttrAccount、kSecAttrService、kSecAttrAccessGroup等)、最后一个是存储加密数据的key(kSecValueData等)
详细说这3个类型的Key:
1、标示类型的key只有一个kSecClass,并且必须设置。
[dic setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];
Value值有5种、详细可以查看开头的链接或者苹果文档(Keychain Item Class Keys and Values节)。但通常我们只用示例里这一种。
这里的Value值不同会影响到SecItem里边存的加密内容以及可以使用的属性Key也有所不同。
2、详细属性key有很多个,并且可以使用的key根据kSecClass设置的值的不同会有不同。常用的就是:
(1)、kSecAttrGeneric(一般属性):
[dic setObject:@"this_is_a_test" forKey:(id)kSecAttrGeneric];
可以不设置,也可以设置,但不影响唯一性。
(2)、kSecAttrAccount(账号):
[dic setObject:@"mmmm" forKey:(id)kSecAttrAccount];
值是一个String,标志唯一的账号。(不设置则视为@””)。
(3)、kSecAttrService(服务):
[dic setObject:@"bbbb" forKey:(id)kSecAttrService];
值是一个String,标志唯一的服务。相当于与kSecAttrAccount一同看成一个联合主键,标志唯一的SecItem。存不同的内容应该使用不同的服务或账号。(不设置则视为@””)
(4)、kSecAttrAccessGroup(允许访问的Group):
[dic setObject:@"XXXXXXX.com.miao.TestApp" forKey:(id)kSecAttrAccessGroup];
如果不设置则自动使用plist里设置的第一个,通常plist里会配置成TeamID+BundleID,既是appID前缀加应用打包设置的BundleID。
关于其他的key,以及其中可以存的数据类型,可以参考苹果文档(Item Class Value Constants节),文档里有详细介绍,并且介绍了每一种kSecClass对应的可以使用的AttrKey。
3、储存数据的key,当SecClass为kSecClassGenericPassword时,我们使用以下代码:
[dic setObject:[NSData data] forKey:(id)kSecValueData];
接受NSData格式的数据,key不能随意改变。
当SecClass为其他值时,key可能会改变,对应接受的数据类型也会改变,详见苹果文档:Value Type Keys
当然你可以不储存数据也能正常保存一个SecItem。
PopupView Example
关于UIView的layout陷阱
1、父View的width设置为负数时。父View的Bound的x会自动变成负数。 之后再将父View的宽度设置为正常值,父View的Bound仍然不会恢复正常(且在UI查看器中显示正常)。此时向此view添加子view,子view不是从父View frame的(0,0)开始,两个View是左右错位的。(父hieght和子view的Bound的y值应该也是同理)
2、IOS8系统中,向UILabel添加子View会被UILabel遮挡(当UILabel的text为空时)、若设置text内容为英文可以恢复正常。设置text含中文时仍然不正常。应避免向UILabel添加子View。