2013年1月2日 星期三

上傳 git repo 到 server 上用作 remote

把 local git repo 上傳到 server 並設定 git remote
假設:

  • 用戶名為 user
  • 伺服器為 server.tld
  • repo 名稱為 myrepo
  • repo 儲存在 /var/repo/ 中
  • remote 名稱為 origin

ssh user@server.tld
mkdir /var/repo/myrepo
exit
tar jcvf myrepo_git.tar.bz2 .git
scp myrepo_git.tar.bz2 user@server.tld:/var/repo/myrepo/
ssh user@server.tld
cd /var/repo/myrepo/
tar jxvf myrepo_git.tar.bz2
git config --bool core.bare true
exit
git remote add origin ssh://user@server.tld/var/repo/myrepo
# try modify some files and commit it to local repo here
git push origin master

2011年11月18日 星期五

在 Objective-C 上 delay 執行一段 code

有時候,我們需要在 Objective-C 上 delay 執行一段 code,該如何處理呢?以往的做法通常需要新增一個 method,再用 [self performSelector:@selector(xxx) withObject:obj afterDelay:1.23] 的方法。幸好,在 iOS 4.0 / Mac OS X 10.6 之後,Apple 加入了 Grand Central Dispatch 技術,可以使用 Objective-C 的 block 而不用新增 method。

- (void)performBlock:(void (^)(void))block afterDelay:(NSTimeInterval)delay
{
 int64_t delta = (int64_t)(1.0e9 * delay);
 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delta), dispatch_get_main_queue(), block);
}

使用方法:

[self performBlock:^{
 // Lines of code
} afterDelay:1.23];

原文 出自 Matthias Plappert。

2010年8月20日 星期五

在 Project 中加入 SVN version 和 Build Count

為方便加入版本資訊,可使用以下 script,在 Project 的 target 中,right click,New Build Phase,New Run Script Build Phase,之後輸入以下 script,Shell 用 /bin/bash 。
之後可以 #import "SVNRevision.h" 取得 SVN_REVISION 數值。
parse_svnversion()
{
    if [[ "$1" = *:* ]]; then
        arr[0]=${1%:*}
        arr[2]=${1//[0-9:]/}
        tmp_arr[1]=${1#*:}
        arr[1]=${tmp_arr[1]//${arr[2]}/}
    else
        arr[2]=${1//[0-9:]/}
        arr[0]=${1//${arr[2]}/}
        arr[1]=${arr[0]}
    fi

    echo $( (( ${arr[0]} > ${arr[1]} )) && echo ${arr[0]} || echo ${arr[1]} )
}

SVN_REV=$(parse_svnversion `svnversion -n`)
echo "#define SVN_REVISION @\"$SVN_REV\"" > "${PROJECT_DIR}/Classes/SVNRevision.h"
exit 0
parse_svnversion 出自 SiegeX 大大,原文在 StackOverflow 上。

2010年6月22日 星期二

NSInvocation 用在 class method 上

為了能簡單地調用 NSInvocation 去 invoke class method (+),特意寫了一個 HWInvocation,是 NSInvocation 的 category,加入了一個新的 constructor。寫完後也順手寫了 instance method (-) 版本的 constructor。
HWInvocation 利用了 Objective-C 的 Variable Arguments 功能,不用 call 無數個 setArgument,可以在 constructor 中一次過輸入所有 arguments。
另外 Sample Code 中示範了怎樣傳 NSObject 和非 NSObject 類變數到 NSInvocation 中,其秘訣是使用 address of (&) 去取得 memory address (pointer)。

SampleCode.m
#import "HWInvocation.h"

// ... other code skipped ...

+ (void)setSomething:(BOOL)yesOrNo str:(NSString *)string
{
 NSLog(@"setSomething: %@ - %@",(yesOrNo == YES ? @"YES" : @"NO"),string);
}

- (void)setOtherThing:(int)num str:(NSString *)string
{
 NSLog(@"setOtherThing: %d - %@",num,string);
}

- testInvocation {
 NSString *str = @"Testing HWInvocation";
 BOOL yes = YES;
 int num = 123;
 NSInvocation *invocation;
 
 invocation = [NSInvocation classMethodInvocationWithSelectorName:@"setSomething:str:" baseClass:[SampleCode class] args:&yes,&str];
 [invocation tryInvoke];
 
 invocation = [NSInvocation invocationWithSelectorName:@"setOtherThing:str:" target:self args:&num,&str];
 [invocation tryInvoke];
}

HWInvocation.h
#import <Foundation/Foundation.h>

@interface NSInvocation (HWInvocation)

+ (NSInvocation *)classMethodInvocationWithSelectorName:(NSString *)selname baseClass:(Class)class args:(void *)buffer, ...;
+ (NSInvocation *)invocationWithSelectorName:(NSString *)selname target:(id)target args:(void *)buffer, ...;
- (BOOL)tryInvoke;

@end
HWInvocation.m
#import "HWInvocation.h"
#import <objc/runtime.h> // Needed for the ISA pointer

@implementation NSInvocation (HWInvocation)

+ (NSInvocation *)classMethodInvocationWithSelectorName:(NSString *)selname baseClass:(Class)class args:(void *)buffer, ...
{
 SEL aSelector;
 NSMethodSignature *signature;
 NSInvocation *invocation;
 int numOfArgs;
 int i = 3; // Index to place the first variable argument
 void *buf;
 va_list argumentList;
 
 aSelector = NSSelectorFromString(selname);
 if (aSelector == NULL) return nil;
 
 signature = [class->isa instanceMethodSignatureForSelector:aSelector];
 if (signature == nil) return nil;
 
 numOfArgs = [signature numberOfArguments];
 
 invocation = [NSInvocation invocationWithMethodSignature:signature];
 if (invocation == nil) return nil;
 
 [invocation setTarget:class];
 [invocation setSelector:aSelector];
 
 if (numOfArgs >= i)
 {
  [invocation setArgument:buffer atIndex:2];
  va_start(argumentList, buffer);
  while (i < numOfArgs)
  {
   buf = va_arg(argumentList, id);
   [invocation setArgument:buf atIndex:i++];
  }
  va_end(argumentList);
 }
 
 return invocation;
}

+ (NSInvocation *)invocationWithSelectorName:(NSString *)selname target:(id)target args:(void *)buffer, ...
{
 SEL aSelector;
 NSMethodSignature *signature;
 NSInvocation *invocation;
 int numOfArgs;
 int i = 3; // Index to place the first variable argument
 void *buf;
 va_list argumentList;
 
 aSelector = NSSelectorFromString(selname);
 if (aSelector == NULL) return nil;
 
 signature = [target methodSignatureForSelector:aSelector];
 if (signature == nil) return nil;
 
 numOfArgs = [signature numberOfArguments];
 
 invocation = [NSInvocation invocationWithMethodSignature:signature];
 if (invocation == nil) return nil;
 
 [invocation setTarget:target];
 [invocation setSelector:aSelector];
 
 if (numOfArgs >= i)
 {
  [invocation setArgument:buffer atIndex:2];
  va_start(argumentList, buffer);
  while (i < numOfArgs)
  {
   buf = va_arg(argumentList, id);
   [invocation setArgument:buf atIndex:i++];
  }
  va_end(argumentList);
 }
 
 return invocation;
}

- (BOOL)tryInvoke
{
 @try
 {
  [self invoke];
  return YES;
 }
 @catch (NSException * e)
 {
  NSLog(@"Invoke failed: %@",NSStringFromSelector([self selector]));
  return NO;
 }
 return NO;
}

@end

2010年6月20日 星期日

Objective-C 神奇的 exchange implementation

在 Objective-C 中,我們可以交換兩個相同 method signature 的 method 內的 implementation,會令 call method A 時實際上運行 method B 的 code,而 call method B 時會運行 method A 的 code。
我們可以利用這個功能,去 "hook" 一些 API,修改其運作方式,對於新手來說這個功能是很危險的,但對於清楚 API 運作的高手來說,這個功能很有用,可以做一些 API 本身沒有的功能。

ExchangeImp.h
@interface NSObject (ExchangeImp)

+ (BOOL)exchangeMethod:(SEL)origSelector withMethod:(SEL)newSelector;

@end

ExchangeImp.m
#import "ExchangeImp.h"

@implementation NSObject (ExchangeImp)

+ (BOOL)exchangeMethod:(SEL)origSelector withMethod:(SEL)newSelector
{
    Method orgMethod = class_getInstanceMethod(self, orgSelector);
    Method newMethod = class_getInstanceMethod(self, newSelector);

    if ((orgMethod != NULL) && (newMethod != NULL))
    {
        if (class_addMethod(self, orgSelector, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
        {
            class_replaceMethod(self, newSelector, method_getImplementation(orgMethod), method_getTypeEncoding(orgMethod));
        }
        else
        {
            method_exchangeImplementations(origMethod, newMethod);
        }
        return YES;
    }
    return NO;
}

@end