2013年7月31日 星期三

用程式抓取Xib(loading Xib programmatically)

if (iPad) {
            self.businessView = [[[NSBundle mainBundle] loadNibNamed:@"BusinessCardView~ipad" owner:self.view options:nil] objectAtIndex:0] ;
        }else{
            self.businessView = [[[NSBundle mainBundle] loadNibNamed:@"BusinessCardView" owner:self.view options:nil] objectAtIndex:0] ;
        }

2013年7月30日 星期二

新增iPad.xib

1,新增YourView~ipad.xib
2,把File's Owner的Custom Class改為YourViewController。
3,最重要的一步:對File's Owner按右鍵,把view跟你剛新增的View做連結。
4,把原來view上的元件copy過來,把該有的連結拉回去YourViewController.h裡。
5,最後,把初始化的地方改為判斷目前device來選用你的View
這裡是用我寫好的singleton為例
static QFunViewController* instance = nil;
+ (QFunViewController*) shareInstance{
    if (instance == nil) {
       
        if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
            instance = [[QFunViewController alloc]initWithNibName:@"QFunViewController" bundle:nil];
        else
            instance = [[QFunViewController alloc]initWithNibName:@"QFunViewController~ipad" bundle:nil];
    }
    return instance;
}

抓取目前螢幕尺寸

//抓觸控尺寸 
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;
 
//抓目前的螢幕解析度
[UIScreen mainScreen] currentMode].size 

2013年7月29日 星期一

對UIImage做左右顛倒的轉換

#import <QuartzCore/QuartzCore.h>

+ (UIImage*)transformImageSymmetrically:(UIImage*)originalImage
{
    UIImage *transformedImage = originalImage;
    if (!isUsingBackCamera) {
 
        //建立一個暫存用的UIImageView
        UIImageView *tempImageView = [[UIImageView alloc] initWithImage:originalImage];
 
        
        UIGraphicsBeginImageContext(tempImageView.frame.size);
        
        //這三行跟下面mark起來的七行,效果是一樣的,可以互相取代
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGAffineTransform flipHorizontal = CGAffineTransformMake(                                                               -1.0, 0.0, 0.0, 1.0, tempImageView.frame.size.width, 0.0 );
        CGContextConcatCTM(context, flipHorizontal);
//        CGImageRef imgRef = originalImage.CGImage;
//        CGFloat width = CGImageGetWidth(imgRef);
//        CGFloat height = CGImageGetHeight(imgRef);
//        CGAffineTransform transform = CGAffineTransformIdentity;  
//        transform = CGAffineTransformMakeTranslation(width,0.0);
//        transform = CGAffineTransformScale(transform, -1.0, 1.0);
//        CGContextConcatCTM(context, transform);
        [tempImageView.layer renderInContext:context];
        
        transformedImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        [tempImageView release];
        
    }
    return transformedImage;
}

2013年7月25日 星期四

從圖片網址轉成UIImage使用

NSURL *url = [NSURL URLWithString:@"http://www.facebook.com/images/devsite/iphone_connect_btn.jpg"];
            NSData *data = [NSData dataWithContentsOfURL:url];
            UIImage *img  = [[UIImage alloc] initWithData:data];

CALayer轉成openGL的texture

貼圖會存在GLuint *tID;

//把UIView的CALayer畫成圖片
- (void)setOverlayLayer:(CALayer *)overlayLayer {
   
    UIImage* image = nil;
   
    UIGraphicsBeginImageContext(overlayLayer.frame.size);
    {
        [overlayLayer renderInContext: UIGraphicsGetCurrentContext()];
        image = UIGraphicsGetImageFromCurrentImageContext();
    }
    UIGraphicsEndImageContext();
   
    // Get the inner CGImage from the UIImage wrapper
    CGImageRef cgImage = image.CGImage;
   
    // Get the image size
    NSInteger width = CGImageGetWidth(cgImage);
    NSInteger height = CGImageGetHeight(cgImage);
   
    // Record the number of channels
    NSInteger channels = CGImageGetBitsPerPixel(cgImage)/CGImageGetBitsPerComponent(cgImage);
   
    // Generate a CFData object from the CGImage object (a CFData object represents an area of memory)
    CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(cgImage));
   
    unsigned char* pngData = new unsigned char[width * height * channels];
    const int rowSize = width * channels;
    const unsigned char* pixels = (unsigned char*)CFDataGetBytePtr(imageData);
   
    // Copy the row data from bottom to top
    for (int i = 0; i < height; ++i) {
        memcpy(pngData + rowSize * i, pixels + rowSize * (height - 1 - i), width * channels);
    }
   
    glClearColor(0.0f, 0.0f, 0.0f, QCAR::requiresAlpha() ? 0.0f : 1.0f);
   
    if (!trackingTIDSet) {
        glGenTextures(1, &tID);
    }

    glBindTexture(GL_TEXTURE_2D, tID);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   
   
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, (GLvoid*)pngData);
   
   
    trackingTIDSet = YES;
    trackingTextureAvailable = YES;
   
    delete[] pngData;
    CFRelease(imageData);
   
    self.renderState = RS_NORMAL;
   
    NSLog(@"setOverlayer");
}

在做這個轉換之前,記得openGL只吃長寬為2的次方的貼圖
因為忽略這個基本觀念,整整花了二天debug得到這個教訓

2013年7月24日 星期三

圖片儲存本機加上callback

 
//你的照片放到theImage 
UIImageWriteToSavedPhotosAlbum(theImage,
   self, // send the message to 'self' when calling the callback
   @selector(thisImage:hasBeenSavedInPhotoAlbumWithError:usingContextInfo:), // the selector to tell the method to call on completion
   NULL); // you generally won't need a contextInfo here
 
//執行callback
- (void)thisImage:(UIImage *)image hasBeenSavedInPhotoAlbumWithError:(NSError *)error usingContextInfo:(void*)ctxInfo {
    if (error) {
        // Do anything needed to handle the error or display it to the user
    } else {
        // .... do anything you want here to handle
        // .... when the image has been saved in the photo album
    }
} 

2013年7月22日 星期一

QCARHelper停止camera 打開camera


////////////////////////////////////////////////////////////////////////////////
// pause the camera view and the tracking of targets
//停止服務
- (void)pauseAR
{
    NSLog(@"QCARutils onPause()");
  
    // If the app status is APPSTATUS_CAMERA_RUNNING, QCAR must have been fully
    // initialised
    if (APPSTATUS_CAMERA_RUNNING == qUtils.appStatus) {
        [qUtils updateApplicationStatus:APPSTATUS_CAMERA_STOPPED];
      
        // QCAR-specific pause operation
        QCAR::onPause();
    }
}


////////////////////////////////////////////////////////////////////////////////
// resume the camera view and tracking of targets
//打開服務
- (void)resumeAR
{
    NSLog(@"QCARutils onResume()");
  
    // If the app status is APPSTATUS_CAMERA_STOPPED, QCAR must have been fully
    // initialised
    if (APPSTATUS_CAMERA_STOPPED == qUtils.appStatus) {
        // QCAR-specific resume operation
        QCAR::onResume();
      
        [qUtils updateApplicationStatus:APPSTATUS_CAMERA_RUNNING];
    }
}

2013年7月18日 星期四

把UIView轉成UIImage

#import <QuartzCore/QuartzCore.h>

+ (UIImage *) imageWithView:(UIView *)view
{
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0);
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];

    UIImage * img = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return img;
}

2013年7月16日 星期二

自己做delegate

一,先新建一個yourDelegateProtocol。
@protocol yourDelegateProtocol <NSObject>
-(void)yourMethod:(NSString *)str withTarget:(NSString*)target;
@end


二,在你要送出delegate的class中宣告你要用來呼叫delegate方法的物件
id <yourDelegateProtocol> delegate;


三,在你要使用delegate的class中的.h宣告這個class要遵守delegate
@interface anotherView : UIView <yourDelegateProtocol>

四,在你原本的viewController中執行delegate物件的方法,即可呼叫所有遵守delegate的方法
    [delegate yourMethod:@"hello" withTarget:@"mylover"];

非同步下載

- (void)downloadWithUrl:(NSString*)targetURL
{
    NSString *urlAsString = targetURL;
    NSURL *url = [NSURL URLWithString:urlAsString];
    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
   
    [NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *responce, NSData *data, NSError *error) {
        if ([data length] > 0 && error == nil) {
            //取得文件目錄
            NSString* documentsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES) objectAtIndex:0];
            //完整檔案路徑
            NSString* filePath = [documentsDir stringByAppendingString:@"ht-inception-360p.mp4"];
            //將資料寫入檔案
            [data writeToFile:filePath atomically:YES];
           
            NSLog(@"成功存檔至%@",filePath);
        }
        else if ([data length] == 0 && error == nil){
            NSLog(@"沒有被下載");
        }
        else if (error != nil){
            NSLog(@"Err : %@",error);
        }
    }];

}

//判斷檔案是否存在
   
    if (![[NSFileManager defaultManager] fileExistsAtPath:@"/你的本地端位置/檔名.mp4"]){
        NSLog(@"檔名.mp4不存在");
    }else{
        NSLog(@"檔名.mp4存在");
    }

2013年7月15日 星期一

connectionDidFinishDownloading下載後無法找到下載檔案

connectionDidFinishDownloading:destinationURL
如果你下載完,去執行
if (![[NSFileManager defaultManager] fileExistsAtPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"yourVideo.mp4"]]){
        //NSLog(@"yourVideo.mp4不存在");
    }else{
        //NSLog(@"yourVideo.mp4存在");
    }
想在destinationURL中找到你剛下載好的資料,
出乎意料的,它竟然一直回傳不存在。
上stackOverflow查完才知道這是因為NSURLConnectionDataDelegate是Newsstand類型的App使用,用來把書報雜誌的內容存到device上。從iOS5~iOS7這個問題仍舊存在,所以如果你是要下載檔案到本地端使用,請使用其他的方式。

2013年7月14日 星期日

FBSession

FB SDK 3.5 在登入之後一定要做 [FBSession setActiveSession:appDelegate.session];
因為SDK中很多method都會直接呼叫activeSession

[appDelegate.session openWithCompletionHandler:^(FBSession *session,                                                         FBSessionState status,                                                         NSError *error) {
       
        if (!error) {
            if ([appDelegate.session.permissions indexOfObject:@"publish_actions"] == NSNotFound) {
                [appDelegate.session requestNewPublishPermissions:@[@"publish_actions",@"photo_upload"]
                                                  defaultAudience:FBSessionDefaultAudienceFriends
                                                completionHandler:^(FBSession *session,
                                                                    NSError *error) {
                                                    // Handle new permissions callback
                                                    appDelegate.session = session;

                                                    [FBSession setActiveSession:appDelegate.session];
                                                }];
                [self updateView];//為何logout的時候也會跑一次這裡!!??
            }
        }
       
       
    }];

2013年7月5日 星期五

FB大頭照的網址

https://graph.facebook.com/100000298980246/picture?type=square

其中100000298980246改成你要的facebook ID

2013年7月4日 星期四

定義一種協定(scheme)讓其他app可以呼叫自己寫的app

一,在.plist中的URL types中的URL schemes 加入自己想要的協定名稱,例如myApp
 (非必要)在URL identifier加入自已想要的identifier文字,例如me.spot0206

二,在AppDelegate實作- (BOOL)application:(UIApplication *)applicationhandleOpenURL:(NSURL*)url {   // Do something withthe url here },用來接收回傳的訊息


三,即可以在其他APP中被呼叫,你可以用safari的網址列來自行測試。
 例如輸入,myapp://?foo=1&amp

四,這裡打的網址就會被接收為下面的url
-(BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
{
    if (!url) {  return NO; }

    NSString *URLString = [urlabsoluteString];
    [[NSUserDefaultsstandardUserDefaults] setObject:URLString forKey:@"url"];
    [[NSUserDefaultsstandardUserDefaults] synchronize];
    return YES;
}

FacebookSDK3.5開始新專案前的設定

一,跳過FB app id申請,直接進入ios app撰寫
二,把解壓好的資料夾中(文件裡的facebooksdk)的FacebookSDKResources.bundle直接拖曳進你的專案。(選項選'Create groups for any added folders' and deselect 'Copy items into destination group's folder (if needed)')




三,在iOS6中,facebookSDK還要用到AdSupport, Accounts, libsqlite3, Security and Social這五個Frameworks.(如果你要build在舊版iOS,記得把不支援的Framework設為Optional)
四,上述動作作好之後,你的Project看起來會像下圖



五,把申請好的Facebook app ID,加入下列二個地方,你就可以開始coding了!
  1. 在.plist中加入FacebookAppID跟FacebookDisplayName,把他的值設好,在fb app設定頁面中都可以找的到你得輸入的值。
  2. 打開URL types,把URL Schemes的item0設為開頭為fb,後面加你的Facebook App ID。

2013年7月2日 星期二

在UIWebView執行JavaScript指令

用簡單的一個method即可達成,stringByEvaluatingJavaScriptFromString

它把指令以string方式讀入,並把回傳值以string的方式接收。


- (NSString*)executeJS
{
    NSString *returnValue = [self.webView stringByEvaluatingJavaScriptFromString:@"marq.appMessage('fb_status','{\"username\":\"LukeSun\",\"profile_pic\":\"http://4-ps.googleusercontent.com/h/www.nownews.com/newspic/1989/i1989627.jpg.pagespeed.ce.wapOg-_ZEz.jpg\" }' )"];
  
  
    NSString* ret = [returnValue stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSLog(@"return string: %@",ret);
    return ret;
}

程式處理網址的encoding跟decoding問題

因為網址列不能存在一些特殊符號,所以這些符號會使用﹪當作逃脫字元來處理
例如%7 = ~
%09 表示 Tab
%20 表示 (1sp) 即一個space鍵
%22 表示 "
%23 表示 #
%25 表示 %
%26 表示 &
%28 表示 (
%29 表示 )
%2B 表示 +
%2C 表示 ,
%2F 表示 /
%3A 表示 :
%3B 表示 ;
%3C 表示 <
%3D 表示 =
%3E 表示 >
%3F 表示 ?
%40 表示 @
%5B 表示[
%5C 表示 \
%5D 表示]
%7C 表示
%7E 表示 ~

在objective-c用下列二個方法做網址的編碼

stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding 會將網址以 UTF-8來編碼。
NSString *encodeURL = [URL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"encode URL: %@", encodeURL);

stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding 會將被編碼的文字以 UTF-8 解碼。
NSString *decodeURL = [encodeURL stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 
NSLog(@"decode URL: %@", decodeURL);
 

2013年7月1日 星期一

An unknown error message 'InstallProhibited', was received from the device.

當安裝程式在實機測試時出現An unknown error message 'InstallProhibited', was received from the device.的錯誤訊息

代表這台機器設定了取用限制,去設定﹣>一般﹣>取用限制,輸入密碼把它解開即可。

NSString NSURL UTF8

//把string以UTF8編碼
NSString* returnValue =
        [URLstring stringByAddingPercentEscapesUsingEncoding:
         NSUTF8StringEncoding];

例如:
//要先將中文地址轉成UTF8型式,才可做為查詢網址。
    NSString* address = [@"台北巿南港區三重路19-11號" stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString: [NSString stringWithFormat:@"http://maps.apple.com/maps?q=%@",address]]];




//NSURL to NSString  NSURL
NSString *returnValue = [URL absoluteString];

在字串中加入雙引號的方式

在VB,用""
在obj c,用\"