2011年8月26日 星期五

Remove UIViewController from UINavigationController


NSMutableArray *allControllers = [[NSMutableArray alloc] initWithArray:navPick.viewControllers];
for (id object in allControllers) {
// if ([object isKindOfClass:[LoginController class]]) // 此行註解掉,會將容器內所有VC移除
[allControllers removeObject:object];
}
navPick.viewControllers = allControllers;

2011年8月24日 星期三

Loaded the "NibFileName" nib but didn't get a UITableView

-[UITableViewController loadView] loaded the "NibFileName" nib but didn't get a UITableView

動態載入時 xcode 會報錯,原因是繼承的形態跟 nib 使用的類別不同造成,
原始的宣告如下:


@interface ObjIDPickViewController : UITableViewController
{
}


要把它改成


@interface ObjIDPickViewController : UIViewController
{
}

2011年8月19日 星期五

C# get a string from C++ DLL

C++ DLL :



TCHAR g_awcMessage[] = L"Hello中文";
char g_aszMessage[] = "Hello中文";

extern "C" __declspec(dllexport) TCHAR* __stdcall GetHelloL()
{
return g_awcMessage;
}

extern "C" __declspec(dllexport) CHAR* __stdcall GetHello()
{
return g_aszMessage;
}

extern "C" __declspec(dllexport) int __stdcall GetInt()
{
return 100;
}



C# P/Invoke:

[DllImport("gpDll.dll")]
public static extern IntPtr GetHello();

[DllImport("gpDll.dll")]
public static extern IntPtr GetHelloL();

[DllImport("gpDll.dll")]
public static extern int GetInt();


private void button1_Click(object sender, EventArgs e)
{
// Not support in CF
//Marshal.PtrToStringAnsi
//Marshal.PtrToStringAuto

// Multibytes 會變成亂碼
string str = Marshal.PtrToStringUni(GetHello());

// Wide Character 顯示正常
string strL = Marshal.PtrToStringUni(GetHelloL());

int n = GetInt();
}

WinCE/Mobile Control Panel Item List

VC++
BOOL ShowControlPanelApplet(int id)
{
TCHAR szParams[32];
SHELLEXECUTEINFO execinfo = {0};
memset(&execinfo, 0, sizeof(execinfo));
execinfo.cbSize=sizeof(execinfo);
execinfo.lpFile=TEXT(“\\windows\\ctlpnl.exe”);
execinfo.lpVerb=TEXT(“open”);


// Id value determines which control applet will be launched
// For e.g. 23 for bluetooth applet
wsprintf(szParams, L”cplmain.cpl,%d”, id);
execinfo.lpParameters = szParams;
BOOL bRet=ShellExecuteEx(&execinfo);
return bRet;
}

VC#
Process.Start(@"\windows\ctlpnl.exe", "cplmain.cpl,19");

Windows Mobile

1 Password
2 Owner Information
3 Power
4 Memory
5 About
6 Brightness
7 Screen
8 Input
9 Sounds & Notifications
10 Remove Programs
11 Menus
12 Buttons
13 Today
14
15 Beam
16 Clocks & Alarms
17 Configure Network Adapters
18 Regional Settings
19 Connections
20
21
22 Manage Certificates
23 Bluetooth
24 Error Reporting
25 GPS Settings
26
27 USB to PC

Windows CE

1 PC Connection - 35#”ctlpnl.exe” \Windows\cplmain.cpl,0
2 Dialing - 35#”ctlpnl.exe” \Windows\cplmain.cpl,1
3 Keyboard - 35#”ctlpnl.exe” \Windows\cplmain.cpl,2
4 Password - 35#”ctlpnl.exe” \Windows\cplmain.cpl,3
5 Owner - 35#”ctlpnl.exe” \Windows\cplmain.cpl,4
6 Power - 35#”ctlpnl.exe” \Windows\cplmain.cpl,5
7 System - 35#”ctlpnl.exe” \Windows\cplmain.cpl,6
8 Display - 35#”ctlpnl.exe” \Windows\cplmain.cpl,7
9 Mouse - 35#”ctlpnl.exe” \Windows\cplmain.cpl,8
10 Stylus - 35#”ctlpnl.exe” \Windows\cplmain.cpl,9
11 Volume & sounds - 35#”ctlpnl.exe” \Windows\cplmain.cpl,10
12 Input Panel - 35#”ctlpnl.exe” \Windows\cplmain.cpl,11
13 Remove Programs - 35#”ctlpnl.exe” \Windows\cplmain.cpl,12
14 Date/Time - 35#”ctlpnl.exe” \Windows\cplmain.cpl,13
15 Certificates - 35#”ctlpnl.exe” \Windows\cplmain.cpl,14
16 Accessibility - 35#”ctlpnl.exe” \Windows\cplmain.cpl,15

SendKeys for .NETCF

Because System.Windows.Forms SendKeys does not support in .NETCF,
So I have to implement it thru APIs,

here is the solutions: SendInput, keybd_event, PostKeybdMessage and SendMessage



[DllImport("coredll.dll", SetLastError = true)]
//[DllImport("user32.dll", SetLastError = true)]
static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);

[DllImport("coredll", SetLastError = true)]
//[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string _ClassName, string _WindowName);

[DllImport("coredll", SetLastError = true)]
//[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);

public static void SendIt()
{
IntPtr ip = FindWindow("notepad", null);


SetForegroundWindow(ip);

const int KEYEVENTF_KEYUP = 0x2;

const int KEYEVENTF_KEYDOWN = 0x0;

byte VK_TAB = 0x0D;

keybd_event(VK_TAB, 0, KEYEVENTF_KEYDOWN, 0);
keybd_event(VK_TAB, 0, KEYEVENTF_KEYUP, 0);
}




Symbolic
constant name
Value
(hexadecimal)
Keyboard (or mouse) equivalent
VK_LBUTTON01Left mouse button
VK_RBUTTON02Right mouse button
VK_CANCEL03Control-break processing
VK_MBUTTON04Middle mouse button (three-button mouse)
VK_BACK08BACKSPACE key
VK_TAB09TAB key
VK_CLEAR0CCLEAR key
VK_RETURN0DENTER key
VK_SHIFT10SHIFT key
VK_CONTROL11CTRL key
VK_MENU12ALT key
VK_PAUSE13PAUSE key
VK_CAPITAL14CAPS LOCK key
VK_ESCAPE1BESC key
VK_SPACE20SPACEBAR
VK_PRIOR21PAGE UP key
VK_NEXT22PAGE DOWN key
VK_END23END key
VK_HOME24HOME key
VK_LEFT25LEFT ARROW key
VK_UP26UP ARROW key
VK_RIGHT27RIGHT ARROW key
VK_DOWN28DOWN ARROW key
VK_SELECT29SELECT key
VK_PRINT2APRINT key
VK_EXECUTE2BEXECUTE key
VK_SNAPSHOT2CPRINT SCREEN key
VK_INSERT2DINS key
VK_DELETE2EDEL key
VK_HELP2FHELP key
300 key
311 key
322 key
333 key
344 key
355 key
366 key
377 key
388 key
399 key
41A key
42B key
43C key
44D key
45E key
46F key
47G key
48H key
49I key
4AJ key
4BK key
4CL key
4DM key
4EN key
4FO key
50P key
51Q key
52R key
53S key
54T key
55U key
56V key
57W key
58X key
59Y key
5AZ key
VK_NUMPAD060Numeric keypad 0 key
VK_NUMPAD161Numeric keypad 1 key
VK_NUMPAD262Numeric keypad 2 key
VK_NUMPAD363Numeric keypad 3 key
VK_NUMPAD464Numeric keypad 4 key
VK_NUMPAD565Numeric keypad 5 key
VK_NUMPAD666Numeric keypad 6 key
VK_NUMPAD767Numeric keypad 7 key
VK_NUMPAD868Numeric keypad 8 key
VK_NUMPAD969Numeric keypad 9 key
VK_SEPARATOR6CSeparator key
VK_SUBTRACT6DSubtract key
VK_DECIMAL6EDecimal key
VK_DIVIDE6FDivide key
VK_F170F1 key
VK_F271F2 key
VK_F372F3 key
VK_F473F4 key
VK_F574F5 key
VK_F675F6 key
VK_F776F7 key
VK_F877F8 key
VK_F978F9 key
VK_F1079F10 key
VK_F117AF11 key
VK_F127BF12 key
VK_F137CF13 key
VK_F147DF14 key
VK_F157EF15 key
VK_F167FF16 key
VK_F1780HF17 key
VK_F1881HF18 key
VK_F1982HF19 key
VK_F2083HF20 key
VK_F2184HF21 key
VK_F2285HF22 key
VK_F2386HF23 key
VK_F2487HF24 key
VK_NUMLOCK90NUM LOCK key
VK_SCROLL91SCROLL LOCK key
VK_LSHIFTA0Left SHIFT key
VK_RSHIFTA1Right SHIFT key
VK_LCONTROLA2Left CONTROL key
VK_RCONTROLA3Right CONTROL key
VK_LMENUA4Left MENU key
VK_RMENUA5Right MENU key
VK_PLAYFAPlay key
VK_ZOOMFBZoom key

Emulate mouse action in .NETCF

There are some ways to do it,



SendMessage API:
//Find topmost window of another application
IntPtr parentWnd = WIN32.Window.FindWindow(null, "Form2");

//Find the button
IntPtr hButton = WIN32.Window.FindWindowEx(parentWnd, IntPtr.Zero, null, "Target");

//Click the target button
WIN32.Window.SendMessage(hButton, Window.WM.WM_LBUTTONDOWN, IntPtr.Zero, IntPtr.Zero);
WIN32.Window.SendMessage(hButton, Window.WM.WM_LBUTTONUP, IntPtr.Zero, IntPtr.Zero);


mouse_event API:

[DllImport("coredll.dll", SetLastError = true)]
static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);

[DllImport("user32.dll")]
static extern bool SetCursorPos(int X, int Y);

public enum MouseEventFlags
{
LEFTDOWN = 0x00000002,
LEFTUP = 0x00000004,
MIDDLEDOWN = 0x00000020,
MIDDLEUP = 0x00000040,
MOVE = 0x00000001,
ABSOLUTE = 0x00008000,
RIGHTDOWN = 0x00000008,
RIGHTUP = 0x00000010
}
void ClickIt()
{
SetCursorPos(400, 10);
mouse_event((int)(MouseEventFlags.LEFTDOWN), 0, 0, 0, 0);
mouse_event((int)(MouseEventFlags.LEFTUP), 0, 0, 0, 0);
}

2011年8月18日 星期四

SAP: Destination configuration already initialized

本篇文章的內容無法解決此問題,請參考此篇才有解答


SAP Connector 要使用時要進行初始:

// 1.初始 SAP 連接介面              
RfcDestinationManager.RegisterDestinationConfiguration(new MyBackendConfig());


這個方法在單執行緒中沒有太大的問題,但是搬到 ASP.NET (web)的世界中就麻煩了,
原因是因為這個方法 RegisterDestinationConfiguration 是靜態方法,

在多執行緒的世界中,程式一不小心就會造成執行階段報錯:Destination configuration already initialized
所以要透過 UnregisterDestinationConfiguration 來進行關閉,
但是要呼叫之前一定要確認傳進去的組態參數是同一個,透過此下的程式碼就可以"沒效率"的解決此問題。

為何說沒效率呢?因為每次呼叫RFC 時,都要 Init & Uninit,浪費資源也浪費時間,
但是目前可能這是唯一的解法,若之後有更好的解決方法再另外補充。

public class HuLane
{
RfcDestination m_rfcDest = null;
RfcRepository m_rfcRepo = null;
HLBackendConfig m_Config = null;

public bool InitSAP()
{
bool bRet = false;
try
{
m_Config = new HLBackendConfig();

RfcDestinationManager.RegisterDestinationConfiguration(m_Config);
m_rfcDest = RfcDestinationManager.GetDestination("JTC_000");
m_rfcRepo = m_rfcDest.Repository;

bRet = true;
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(
String.Format("InitSAP(): {0}", ex.Message));
}

return bRet;
}

public bool UninitSAP()
{
bool bRet = false;
try
{
RfcDestinationManager.UnregisterDestinationConfiguration(m_Config);
bRet = true;
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(
String.Format("UninitSAP(): {0}", ex.Message));
}

return bRet;
}
}



參考資料來源連結

IRfcTable、DataTable、DataSet 資料轉換模組

撰寫 SAP RFC 應用時,一定會遇到資料轉換的問題,
撰寫成公用模組,可以很方便的叫用。



public static DataTable GetDataTableFromRfcTable(IRfcTable rfcTable)
{
DataTable dtRet = new DataTable();

for (int liElement = 0; liElement < rfcTable.ElementCount; liElement++)
{
RfcElementMetadata rfcEMD = rfcTable.GetElementMetadata(liElement);
dtRet.Columns.Add(rfcEMD.Name);
}

foreach (IRfcStructure row in rfcTable)
{
DataRow dr = dtRet.NewRow();

for (int liElement = 0; liElement < rfcTable.ElementCount; liElement++)
{
RfcElementMetadata rfcEMD = rfcTable.GetElementMetadata(liElement);
dr[rfcEMD.Name] = row.GetString(rfcEMD.Name);
}

dtRet.Rows.Add(dr);
}

return dtRet;
}

public static DataTable[] GetDataTablesFromRfcTables(IRfcTable[] rfcTables)
{
DataTable[] dtRetTables = null;

if (rfcTables.Length > 0)
{
dtRetTables = new DataTable[rfcTables.Length];

for (int i = 0; i < rfcTables.Length; i++)
{
dtRetTables[i] = GetDataTableFromRfcTable(rfcTables[i]);
}
}

return dtRetTables;
}

public static DataTable[] GetDataTablesFromDataSet(DataSet ds)
{
DataTable[] dtRetTables = new DataTable[ds.Tables.Count];

for (int i = 0; i < ds.Tables.Count; i++)
dtRetTables[i] = ds.Tables[i];

return dtRetTables;
}

public static DataSet GetDataSetFromDataTables(DataTable[] dtTables)
{
DataSet dsRet = new DataSet();

for (int i = 0; i < dtTables.Length; i++)
{
dsRet.Tables.Add(dtTables[i]);
}

return dsRet;
}

2011年8月15日 星期一

呼叫 SAP RFC - 傳入 IRfcTable

由呼叫 SAP RFC得知,呼叫 RFC 和一般寫程式的概念大同小異,
相關的元素可是一樣都沒有少(輸出入參數、宣告呼叫方法),
接下來講的是如何把 IRfcTable 當作輸入的參數傳入 SAP RFC 中,

要傳入 IRfcTable 到 SAP RFC 中,有分為以下幾個步驟:

1.初始 SAP 連接介面
2.設定 SAP 連接參數
3.初始 SAP RFC 來源
4.建立 IRfcTable 結構
5.設定 IRfcTalbe 參數
6.呼叫 SAP RFC 返回值
7.取得 SAP RFC 返回值

實際上透過程式碼的實作如下:

using SAP.Middleware.Connector;


using System;
using System.Linq;
using System.Text;
using SAP.Middleware.Connector;


namespace csSAP
{
class Program
{
static void Main(string[] args)
{
// 1.初始 SAP 連接介面
RfcDestinationManager.RegisterDestinationConfiguration(new MyBackendConfig());

//2.設定 SAP 連接參數
RfcDestination prd = RfcDestinationManager.GetDestination("PRD_000");
try
{

//3.初始 SAP RFC 來源
RfcRepository repo = prd.Repository;
IRfcFunction IFunciton = repo.CreateFunction("JTC_BR0002");

//4.建立 IRfcTable 結構
IFunciton.Invoke(prd);
IRfcTable Itab = IFunciton.GetTable("IT_JTC"); // 取得 SAP 中定義的表格結構

//5.設定 IRfcTalbe 參數
Itab.Append(); // 加入一筆record 到表格中
Itab[0].SetValue("FIELD1", "1000");
Itab[0].SetValue("FIELD2", "1001");

Itab.Append(); // 再加入一筆record 到表格中
Itab[1].SetValue("FIELD1", "1001");
Itab[1].SetValue("FIELD2", "1002");

//6.呼叫 SAP RFC 返回值
IFunciton.SetValue("IT_JTC", Itab);
IFunciton.Invoke(prd);

//7.取得 SAP RFC 返回值
IRfcTable IRetTab = IFunciton.GetTable("ET_RETURN");

}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}

public class MyBackendConfig : IDestinationConfiguration
{
public RfcConfigParameters GetParameters(String destinationName)
{
if ("JTC_000".Equals(destinationName))
{
RfcConfigParameters parms = new RfcConfigParameters();
parms.Add(RfcConfigParameters.AppServerHost, "192.168.1.1");
parms.Add(RfcConfigParameters.SystemNumber, "00");
parms.Add(RfcConfigParameters.User, "UserName");
parms.Add(RfcConfigParameters.Password, "UserPassword");
parms.Add(RfcConfigParameters.Client, "100");
parms.Add(RfcConfigParameters.PoolSize, "5");
parms.Add(RfcConfigParameters.MaxPoolSize, "10");
parms.Add(RfcConfigParameters.IdleTimeout, "600");
parms.Add(RfcConfigParameters.SystemID, "JTC");
return parms;
}
else return null;
}
// The following two are not used in this example:
public bool ChangeEventsSupported()
{
return false;
}
public event RfcDestinationManager.ConfigurationChangeHandler ConfigurationChanged;
}
}

2011年8月13日 星期六

Why NSString* retainCount is 2147483647

先來看以下這段程式碼:

NSString *test1 = @"Test string";
NSLog(@"test1 retain count is: %d", [test1 retainCount]);	// 2147483647
[test1 retain];
NSLog(@"test1 retain count is: %d", [test1 retainCount]);	// 2147483647
[test1 release];
NSLog(@"test1 retain count is: %d", [test1 retainCount]);	// 2147483647

恩,你沒看錯,印出來的 retainCount 都是 2147483647,
接著我們再來看下面這段程式碼:

NSString *test2 = [[NSString alloc] initWithString:@"Test string"];
NSLog(@"test 2 retain count is: %d", [test2 retainCount]);	// 猜猜看
[test2 retain];
NSLog(@"test 2 retain count is: %d", [test2 retainCount]);	// 猜猜看
[test2 release];
NSLog(@"test 2 retain count is: %d", [test2 retainCount]);	// 猜猜看


恩,印出來的值有符合預期的物件參考值:1 2 1 嗎?
答案是沒有,同樣都是 2147483647 這個神奇數字,這個數字到底是什麼東西呢?

其實上述的寫法,在經過 xcode compiler 編譯之後,都會把它改成一個指向常數字串的指標,
而這個神奇的數字,就是因為指標指向常數的時候,使用 retainCount 只會印出 UINT_MAX,
實際上看以下的圖就會更瞭解:



接著再來看這段程式碼:

NSString *test3 = [[NSString alloc]initWithFormat:@"%@", @"Test string"];
NSLog(@"test 3 retain count is: %d", [test3 retainCount]);	// 1	
[test3 retain];
NSLog(@"test 3 retain count is: %d", [test3 retainCount]);	// 2
[test3 release];
NSLog(@"test 3 retain count is: %d", [test3 retainCount]);	// 1	

這樣就有符合預期的參考值了,差異就在 initWithFormat 這個初始字串的方式,
看出差異了嗎?

資安監控 商機無限大

自從電腦被發明,貝爾實驗室出現了第一隻病毒,到現在的智慧型手機資安問題,
讓很多從事資訊安全的公司發跡,舉凡防毒軟體、監控軟體..,除了防毒軟體之外,
還有許多型態的資安系統,都是有利可圖、商機無限的方向。

智慧型手機的時代已經來臨了,原本在PC上的應用紛紛的搬到可攜裝置上來,
先來看要錢的:
http://www.youtube.com/watch?v=KuM9egbfwQ4

再來看免錢的:
http://portable.easylife.tw/2722

上述的都是就現有的系統架構下,讓管理監控人員可以方便的在可攜裝置上"控管"。

另外還有一種是控管使用電腦(或可攜裝置)的系統:
http://www.ip-guard.com/

恩...商機無限,而且說實在,
進入的門檻還在可以負擔的範圍內,
值得好好的思考。

2011年8月12日 星期五

Invalid key issue for android APP to call facebook API.

使用 SAP GUI

SAP 提供了 GUI 讓開發操作人員使用,在 .NET 整合開發的階段透過此工具尤其有用,
實務上文件常常跟不上實際的系統變動,直接透過 SAP GUI 進去看 RFC 宣告的輸出入參數比較實在。



呼叫 SAP RFC

要呼叫 SAP RFC 取得值,有分為以下幾個步驟:

1.初始 SAP 連接介面
2.設定 SAP 連接參數
3.初始 SAP RFC 來源
4.呼叫 SAP RFC 函數
5.取得 SAP RFC 返回值

實際上透過程式碼的實作如下:

using SAP.Middleware.Connector;


using System;
using System.Linq;
using System.Text;
using SAP.Middleware.Connector;

namespace csSAP
{
class Program
{
static void Main(string[] args)
{
// 1.初始 SAP 連接介面
RfcDestinationManager.RegisterDestinationConfiguration(new MyBackendConfig());

//2.設定 SAP 連接參數
RfcDestination prd = RfcDestinationManager.GetDestination("JTC_000");
try
{

//3.初始 SAP RFC 來源
RfcRepository repo = prd.Repository;

//4.呼叫 SAP RFC 函數
IRfcFunction stfcReader = repo.CreateFunction("BAPI_COMPANY_GETDETAIL");

// 設定要傳入的參數
stfcReader.SetValue("COMPANYID", "1010");

stfcReader.Invoke(prd);

//5.取得 SAP RFC 返回值
string strRet = stfcReader.GetStructure("COMPANY_DETAIL").GetString("NAME1");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}

public class MyBackendConfig : IDestinationConfiguration
{
public RfcConfigParameters GetParameters(String destinationName)
{
if ("JTC_000".Equals(destinationName))
{
RfcConfigParameters parms = new RfcConfigParameters();
parms.Add(RfcConfigParameters.AppServerHost, "192.168.1.1");
parms.Add(RfcConfigParameters.SystemNumber, "00");
parms.Add(RfcConfigParameters.User, "UserName");
parms.Add(RfcConfigParameters.Password, "UserPassword");
parms.Add(RfcConfigParameters.Client, "100");
parms.Add(RfcConfigParameters.PoolSize, "5");
parms.Add(RfcConfigParameters.MaxPoolSize, "10");
parms.Add(RfcConfigParameters.IdleTimeout, "600");
parms.Add(RfcConfigParameters.SystemID, "JTC");
return parms;
}
else return null;
}
// The following two are not used in this example:
public bool ChangeEventsSupported()
{
return false;
}
public event RfcDestinationManager.ConfigurationChangeHandler ConfigurationChanged;
}
}

2011年8月11日 星期四

Xcode crush

不管是 MS Visual Studio, Apple Xcode, Java Eclipse 全部都被我操到當掉,該自豪嗎...

NSString 常用操作範例


1.字串比較
NSString *str1 = [[NSString alloc]initWithString:@"I am String1"];
NSString *str2 = [[NSString alloc]initWithString:@"I am String2"];
NSLog(@"%@ 與 %@ 是否相同: %@", str1, str2, [str1 isEqualToString:str2] ? @"Y":@"N");
[str1 release];
[str2 release];


2.字串比較(不區分大小寫)
NSString *str1 = [[NSString alloc]initWithString:@"I am String1"];
NSString *str2 = [[NSString alloc]initWithString:@"i am string1"];
NSLog(@"%@ 與 %@ 是否相同(不考慮大小寫): %@", str1, str2,
[str1 caseInsensitiveCompare:str2]==NSOrderedSame ? @"Y":@"N");
[str1 release];
[str2 release];

3.搜尋字串
NSString *str1 = [[NSString alloc]initWithString:@"This is an apple"];
//此處NSRange 為區分大小寫
NSRange searchString1 = [str1 rangeOfString:@"apple"];
NSRange searchString2 = [str1 rangeOfString:@"orange"];
NSLog(@"%@ 是否有apple字串: %@",str1, searchString1.location == NSNotFound ? @"N" : @"Y" );
NSLog(@"%@ 是否有orange字串: %@",str1, searchString2.location == NSNotFound ? @"N" : @"Y" );
[str1 release];

4.取出字串
NSString *str1 = [[NSString alloc]initWithString:@"this is a string"];
NSLog(@"%@ 取出從頭自第2位(不包含第2位)的字串: %@",str1, [str1 substringToIndex:1]);
NSLog(@"%@ 取出第2位(包含) 後所有字串: %@",str1, [str1 substringFromIndex:1]);
NSLog(@"%@ 取出第3位至第7位的字串: %@",str1, [str1 substringWithRange:NSMakeRange(5,4)]);
[str1 release];

5.替換字串
NSString *string1 = [[NSString alloc]initWithString:@"this is a book"];
NSString *string2 = [[NSString alloc]initWithString:@"pen"];
NSLog(@"%@ 替換後 %@",string1,
[string1 stringByReplacingOccurrencesOfString:@"book" withString:@"pen"]);
[string1 release];
[string2 release];

6.字串轉成array
NSString *str1 = [[NSString alloc]initWithString:@"apple,orange,cat,dog,bird"];
NSLog(@"%@",[str1 componentsSeparatedByString:@","]);
[str1 release];

7.array轉成字串
NSArray *array = [[NSArray alloc]initWithObjects:@"apple",@"orange",@"cat",@"bird",nil];
NSLog(@"%@",[array componentsJoinedByString:@","]);
[array release];

NSString 轉換為 NSDate

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];

[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSDate *date = [dateFormatter dateFromString:@"2010-08-04 16:01:03"];
NSLog(@"%@", date);
[dateFormatter release];

2011年8月7日 星期日

.NET with SAP RFC

SAP 開發者資源


早期的 SAP Connector 2.0 只有支援 .NET Framework 1.1,
需要安裝的是 sapnco30,安裝完畢之後,在 IDE 中手動加入參考,
瀏覽至安裝的資料夾中,引用 sapnco.dll 及 sapnco_utils.dll。

主要的功能都在下面的 namespace 中:
using SAP.Middleware.Connector;

2011年8月4日 星期四

sendSynchronousRequest 狀態下如何顯示忙碌訊息

NSURLConnection 類別中的 sendSynchronousRequest 方法,
是一個同步處理的機制,也就是說當此方法ㄧ被呼叫,該執行緒就會被整個咬住了,
通常來說我們會希望能加入一些畫面提醒的機制(例如轉圈圈),有兩種解決來提供:

解法一(程式碼可以改最少):
- (void)loadInOnePart {

//...other real code

UIAlertView *avBusy = [[[UIAlertView alloc] initWithTitle:@"Busy busy" message:nil delegate:nil
cancelButtonTitle:nil otherButtonTitles:nil] autorelease];
[avBusy show];

UIActivityIndicatorView *aiBusy = [[[UIActivityIndicatorView alloc]
initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite] autorelease];
[aiBusy startAnimating];
[avBusy addSubview:aiBusy];

aiBusy.center = CGPointMake(avBusy.bounds.size.width / 2, avBusy.bounds.size.height / 2 + 10);

[[NSRunLoop currentRunLoop] runUntilDate:[NSDate date]];

[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

[avBusy dismissWithClickedButtonIndex:0 animated:YES];
}

解法二(程式碼分割要考慮整體架構):
- (void)loadPart1 {
activityIndicator = [[[UIActivityIndicatorView alloc]
initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]
autorelease];
[self.view addSubview:activityIndicator];
[activityIndicator startAnimating];
[self performSelector:@selector(loadPart2) withObject:nil afterDelay:0];
}

- (void)loadPart2 {
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
[activityIndicator stopAnimating];
}


參考資料來源