2013년 8월 30일 금요일

메모리 관리 Tip



- (void)dealloc
{
    CCArray* children = [self children];
    for(CCNode* tempNode in children)
    {
        if(tempNode != nil && 1 < [tempNode retainCount])
        {
            while(1 < [tempNode retainCount])
            {
                [tempNode release];
            }
        }
    }
 
    [[CCTextureCache sharedTextureCache] removeAllTextures];
    [super dealloc];
}

CCLayer에 addChild가 된 모든 CCSprite 이미지들을 배열로 만들어서 해당 배열의 모든 객체의 retainCount를 확인하고 release해주는 코드이다.

확장메서드

확장 메서드의 세가지 선언 규칙
  • static 클래스 안에 구현되어야 한다.
  • static 메서드로 선언되어야 한다.
  • 항상 첫 번째 파라미터에는 본인이 포함될 타입을 지정한다. 그리고 지정된 타입 앞에는 this 키워드가 위치해야 한다.
public static class ExtensionString
{
    public static string LongStringLimit(this StringBuilder src, int limitLength)
    {
        string limit = src.ToString();
 
        if (src != null) src = null;
        if (limit.Length <= limitLength) return limit;
        else 
        {
            limit = limit.Substring(0, limitLength);
            return String.Format("{0}...", limit);
        }
    }
}

Execute CRUD-LINQ

ExecuteCommand : 요청할 쿼리문과 쿼리문에 적용할 파라미터를 전달받아 실행하고 실행 결과를 int 타입으로 리턴한다.
                                이 값은 쿼리문이 실행된 이후에 영향받은 데이터 건수를 가진다.

Select


IEnumerable<Products> result = north.ExecuteQuery<Products>
            ("Select * from products where unitprice >= {0}", 100);
foreach(Products prod in result)
{
    Console.WriteLIne("ProductID : {0}, Unit Price : {1}", 
                      prod.ProductID, 
                      prod.UnitPrice);
}

Insert, Update, Delete

public void ExecuteCommandTest()
{
    const string insertProd = "insert into products values({0}, {1}, {3}, {4}, {5})";
    const string updateProd = "update products set UnitPrice = UnitPrice + 2.00 where UnitPrice >= {0}";
    const string deleteProd = "delete products where unitprice >= {0}";
 
    try
    {
        int insertAffectedCnt = north.ExecuteCommand(insertProd, "Test Prod",
                                                     10,         1,
                                                     "31 boxes", 7.00,
                                                     61);
        int updateAffectedCnt = north.ExecuteCommand(updateProd, 100);
        int deleteAffectedCnt = north.ExecuteCommand(deleteProd, 100);
  
        //변경 사항을 데이터베이스에 반영
        north.SubmitChanges();
 
        //추가, 수정, 삭제 처리 후 영향받은 데이터 건수 체크
        Console.WriteLine("추가된 건 수 : {0} 수정된 건 수 : {1} 삭제된 건 수 : {2}",
                      insertAffectedCnt, updateAffectedCnt, deleteAffectedCnt);
    }
    catch(Exception ex){ Console.WriteLine(ex.Message); }
}

저장프로시저와 함수 - LINQ

저장프로시저를 이용한 다중테이블 입력 방법
예 : Customers와 CustomersInfo 두 테이블 있고 회원가입시
       Customers에는 UserName, Password, Email을 입력하고
       CustomerInfo에는 FullName과 Customers에 Primary Key인 CustomerID를 입력한다면

DB에 Stored Procedure 생성

CREATE PROCEDURE [InsertCust]
@Username VARCHAR(10),
@Password CHAR(40),
@Email VARCHAR(100),
@Fullname NVARCHAR(10)
AS
DECLARE @CustomerID INT;
BEGIN TRY
    INSERT INTO [Customers] VALUES(@Username, @Password, @Email);
    SELECT @CustomerID = [CustomerID] FROM [Customers] WHERE [UserName] = @Username;
    INSERT INTO [CustomerInfo]([CustomerID], [FullName]) VALUES(@CustomerID, @Fullname);
END TRY

BEGIN CATCH
    RETURN ERROR_NUMBER()
END CATCH
GO

Entity설정

[Function(Name="dbo.InsertCust")]
public int InsertCust(
    [Parameter(Name="Username",DbType="VarChar(10)")] string username,
    [Parameter(Name="Password",DbType="Char(40)")]    string password,
    [Parameter(Name="Email",DbType="VarChar(100)")]   string email,
    [Parameter(Name="FullName",DbType="NVarChar(30)")]string fullname)
    {
        IExecuteResult result = this.ExecuteMethodCall(
        this,
        ((MethodInfo)(MethodInfo.GetCurrentMethod())),
        username, password, email, fullname);
    return ((int)(result.ReturnValue));
}

사용방법

CustomersEntity entity = new CustomersEntity(conn);
int insert = entity.InsertCust("tomebody", "han001122", "tome@naver.com", "Tome kim");
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-

저장프로시저를 이용한 다중테이블 조회 방법
예 : CustomerInfo, Products, Orders 3개의 테이블이 있다고 가정
       CustomerInfo에서는 FullName,
       Products에서는 ProductName,
       Orders에서는 UnitPrice, Amount를 읽어온다.
       단 CustomerID, ProductID를 기준값으로

DB에 Stored Procedure 생성


CREATE PROCEDURE [SelectOrderInfo] @CustomerID INT, @ProductID INT
AS
    SELECT c.FullName, p.ProductName, o.Quantity, (o.Quantity * p.UnitPrice) AS [Amount]
    FROM [CustomerInfo] c
    JOIN [Orders] o
    On c.CustomerID = o.CustomerID
    JOIN [Products] p
    On o.ProductID = p.ProductID
    WHERE c.CustomerID = @CustomerID And o.ProductID = @ProductID
GO

Entity설정


[Function(Name="dbo.SelectOrderInfo")]
public ISingleResult<SelectOrderInfoResult> SelectOrderInfo(
    [Parameter(Name="CustomerID",DbType="Int")]int CustomerID,
    [Parameter(Name="ProductID",DbType="Int")]int ProductID)
{
    IExecuteResult result = this.ExecuteMethodCall(
        this,
        ((MethodInfo)(MethodInfo.GetCurrentMethod())),
        CustomerID, ProductID);
    return((ISingleResult<SelectOrderInfoResult>)(result.ReturnValue));
}

public partial class SelectOrderInfoResult
{
    [Column]public string FullName { get; set; }
    [Column]public string ProductName { get; set; }
    [Column]public int Quantity { get; set; }
    [Column]public int Amount { get; set; }
}
SelectProcedure entity = new SelectProcedure(conn);

Entity설정

ISingleResult<SelectOrderInfoResult> Result = entity.SelectOrderInfo(1, 1);
foreach (SelectOrderInfoResult item in Result)
{
    Console.WriteLine("{0}-{1}-{2}-{3}",
        rs.FullName,
        rs.ProductName,
        rs.Quantity,
        rs.Amount);
}

-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
ISingleResult<TEntity> : 저장 프로시저의 실행 결과로 리턴되는 엔티티 클래스의 단일 결과집합을 가진다.

델리게이트와 익명 메서드

C#에서 델리게이트는 delegate라는 키워드를 통해 선언되며 리턴 타입과 파라미터도 가질 수 있다. 또한 new 연산자를 통해 인스턴스를 생성하여 사용된다. 델리게이트가 갖는 리턴 타입과 파라미터는 그가 처리하는 메서드에 종속적이다.
대리자는 메서드를 다른 메서드에 인수로 전달하는데 사용된다.

예
// Declare delegate -- defines required signature:
delegate double MathAction(double num);

class DelegateTest
{
    // Regular method that matches signature:
    static double Double(double input)
    {
        return input * 2;
    }

    static void Main()
    {
        // Instantiate delegate with named method:
        MathAction ma = Double;

        // Invoke delegate ma:
        double multByTwo = ma(4.5);
        Console.WriteLine(multByTwo);

        // Instantiate delegate with anonymous method:
        MathAction ma2 = delegate(double input)
        {
            return input * input;
        };

        double square = ma2(5);
        Console.WriteLine(square);

        // Instantiate delegate with lambda expression
        MathAction ma3 = s => s * s * s;
        double cube = ma3(4.375);

        Console.WriteLine(cube);
    }
}


List<int> list = new List<int>();
list.AddRange(new int[] { 100, 200, 300, 400, 500, 600 });
ICollection<int> result = list.FindAll(delegate(int item) { return item > 350; });
foreach (int a in result)
{
    Console.WriteLine(a);
}

제네릭 형식 정의와 사용

1. using System.Collections.Generic
2. 제한 사항과 제약 사항
   
제한사항 
  1. 제네릭이 적용된 클래스는 ContextBoundObject 클래스로부터 파생될 수 없다.
  2. 열거형에 사용될 수 없다.
  3. Replection을 이용해서 생성되는 동적 메서드는 제네릭 형식을 취할 수 없다.
 -제약사항 : 제네릭 클래스 레벨에서 선언될 경우 선언하는 클래스에 몇 가지의 제약 사ㅏ항을 지정할 수 있다.  이 제약 사항은 SQL문에서 where절에서 사용하는 것과 의미가 동일하다.
예 :

//IDisposable을 구현하는 T
class GenericConstraint<T> where T : IDisposable{}
//class 타입 T, 구조체 타입 U
class GenericConstraint<T, U> where T : class where U : struct{}
//IComparable을 구현하고, 파라미터가 없는 기본 생성자를 가진 타입 T
class GenericConstraint<T> where T : IComparable, new()

//델리게이터에 파라미터가 없는 기본생성자를 가진 타입 T
delegate T GenericDelegate<T>(T val) where T : new();

Dictionary<TKey, TValue>
Dictionary<int, string> colorDic = new Dictionary<int, string>();
//key와 value를 쌍으로 저장
colorDic.Add(1, "Red");
//값 변경
colorDic[1] = "Black";
//key가 3인 color 값 조회
string blackColor = string.Empty;
if(colorDic.TryGetValue(3, out blackColor))
{
    Console.WriteLine("key가 3으로 저장된 Color는 {0}", blackColor);
}
//key가 4인 데이터 존재 유무 확인
if(!colorDic.ContainsKey(4))
{
    colorDic.Add(4, "Yellow");
}
//key값만 가지는 컬렉션 객체 생성
Dictionary<int, string>.KeyCollection keyCollection = colorDic.Keys;
foreach(int key in keyCollection)
{
    Console.WriteLine(key);
}
//value값만 가지는 컬렉션 객체 생성
Dictionary<int, string>.ValueCollection valueCollection = colorDic.Values;
//key와 value를 쌍으로 가지는 컬렉션의 요소 조회
foreach(KeyValuePair<int, string> keyValue in colorDic)
{
    Console.WriteLine("key {0}의 Color는 {1}", keyValue.Key, keyValue.Value); 
}
*TryGetValue 메서드는 key값을 기준으로 해당 데이터를 out파라미터로 전달한다.
List<T>
예:
List<int> list = new List<int>();
list.Add(100);
//컬렉션의 현재 배열 크기 조회
Console.WriteLine("컬렉션의 현재 배역 크기는 {0}", list.Capacity);
//컬렉션의 현재 저장 데이터 개수 조회
Console.WriteLine("컬렉션에 저장된 요소의 개수는 {0}", list.Count);
//1번째에 데이터 저장
list.Insert(1, 500);
//1번째에 저장된 데이터 조회
Console.WriteLine("1번째 데이터는 {0}", list[1]);
//1번째에 데이터 삭제
list.RemoveAt(1);
//컬렉션의 배열 크기를 조정
list.TrimExcess();
TrimExcess() : 동적 배열 크기를 갖는 클래스에서 공통적으로 사용되는 메서드로 호출후의 배열 크기는 컬렉션에 저장되어 있는 요소의 개수와 동일해 진다.
SortedList<TKey, TValue>
예:
// 컬렉션 인스턴스 생성
SortedList<int, string> colorSort = new SortedList<int, string>();
// 데이터 저장
colorSort.Add(1, "Red");
colorSort.Add(3, "Green");
colorSort.Add(2, "Blue");
// 저장된 데이터 조회
foreach (KeyValuePair<int, string> color in colorSort)
{
    Console.WriteLine(color.Value);
}
// 컬렉션의 배열 크기 조회
Console.WriteLine("현재 컬렉션의 배열 크기 : {0}", colorSort.Capacity);
// 컬렉션 배열 크기 조정
colorSort.TrimExcess();
// 첫 번째 배열 크기 및 요소 개수 조회
Console.WriteLine("첫 번째 TrimExcess 호출 후 컬렉션 배열 크기:{0}, 요소 개수:{1}", colorSort.Capacity, colorSort.Count);
// key 값이 2인 데이터 삭제
colorSort.RemoveAt(2);
// 컬렉션 배열 크기 조정
colorSort.TrimExcess();
// 두 번째 배열 크기 및 요소 개수 조회
Console.WriteLine("두 번째 TrimExcess 호출 후 컬렉션 배열 크기:{0}, 요소 개수:{1}", colorSort.Capacity, colorSort.Count );

LinkedList<T>
Queue<T>
Stack<T>

C# String & 정규식




string.Replace(‘원본’,’교체’)
string.Insert(‘Index’, ‘삽입할 데이터’)
string.Substring(‘start_index’, ‘end_index’)
string.StartsWith(‘MachingString’)

{N[,M][:formatString]}
N 0부터 시작하는 인덱스값으로 대치될 인수를 나타낸다.
M 값은 대치될 값이 표시될 자리 수를 나타낸다. 만약 인수의 길이가 이 M 값보다 작으면 공란이 포함되어 표시된다.

   만약 M값을 음수로 지정하면 대치되는 인수는 왼쪽 정렬로 표시되고, 만약 M 값을 양수로 지정하면 오른쪽 정렬로

   표시된다.
formatString 선택 포맷 코드 string이다.

문자형식
C or c  통화
D or d10진법
E or e공학용(지수)
F or f고정 소수점
G or g일반
N or n번호, 이와 비슷한 F는 천 단위마다 컴마가 추가된다.
P or p퍼센트
R or r라운드 트립, string으로 변경된 numeric 타입이 원래의 numeric값으로 원 위치될 수 있게 보장한다. 부동소수점일 때만 지원한다.
X or x



/////////////////////////////////////////////////////////////////////
int i = 123456;
{0:C} : $123456 {0:C5} : $123456.00000
{0:D} : 123456 {0:D5} : 123456
{0:E} : 1.234560E+005 {0:E5} : 1.234560E+005
{0:F} : 123456.00 {0:F5} : 123456.00000
{0:G} : 123456 {0:G5} : 123456
{0:N} : 123,456.00 {0:N5} : 123,456.00000
{0:P} : 12,345,600.00 % {0:P5} : 12,345,600.00 %
{0:X} : 1E240 {0:X5} : 1E240
/////////////////////////////////////////////////////////////////////


형식문자사용 용도설명
00자리 표시자 표시숫자가 형식상 0보다 적은 숫자라면 nonsignificant 0으로 표시
#숫자 자리 표시자 표시파운드 표시(#)를 significant숫자로만 대체
.10진수의 점을 표시마침표 표시
,그룹 구분자1,000처럼 숫자 즈룹을 구분
%퍼센트 표시퍼센트(%) 표시
E+0
E-0
e+0
e-0
지수 표시지수 결과 형식으로 표시
\문자 표시“\n”처럼 전통적인 형식 시퀀스와 함깨 사용
‘ABC’문자 string따옴표나 쌍따옴표 내에 모둔 종류의 string 표시
;부분 구분자숫자값이 양수, 음수, 0에 따라 다른 결과값을 지정


/////////////////////////////////////////////////////////////////////
int i = 123456     
{0:#0}   123456
{0:#0;(#0)}    123456
{0:#0;(#0);<zero>} 123456
{0:#%} 12345600%

int j = -123456   
{0:#0}   -123456
{0:#0;(#0)}    (123456)
{0:#0;(#0);<zero>} (123456)
{0:#%} -12345600%

int x = 0
{0:#0}   0
{0:#0;(#0)}    0
{0:#0;(#0);<zero>} <zero>
{0:#%} %
/////////////////////////////////////////////////////////////////////
StringBuilder
.Replace(‘원본’, ‘교체’)
.Insert(index, ‘data’)
.Append(‘data’)
.AppendFormat(“{0:3}”, ‘data’)
.Remove(start_index, end_index)

정규식
설명
.“\n”이외의 모든 단일 문자를 찾는다.
[characters]목록에서 단일 문자를 찾는다.
[^characters]목록에 없는 단일 문자를 찾는다.
[charX-charY]지정된 범위에서 단일 문자를 찾는다.
\w[a-zA-Z_0-9]와 같은 단어 문자를 찾는다.
\W단어가 아닌 문자를 찾는다.
\s[\n\r\t\f]와 같은 공백 문자를 찾는다.
\S공백이 아닌 문자를 찾는다.
\d[0-9]와 같은 10진수를 찾는다.
\D숫자가 아닌 문자를 찾는다.
^줄 시작
$줄의 마지막
\b단어 경계
\B단어 경계가 아닌 부분
*0개 이상 찾는다.
+1개 이상 찾는다.
?0개나 한 개 찾는다.
{n}정확히 n개 찾는다.
{n,}최소한 n개인 것을 찾는다.
{n,m}최소 n개 최대 m개인 것을 찾는다.
()일치하는 substring을 캡처한다.
(?<name>)일치하는 substring을 그룹 이름으로 캡처한다.
|논리적 OR


Match
static void Main(string[] args)
{
    Regex r = new Regex(“in”);
    Match m = r.Match(“Matching”);
    if(m.Success)
    {
        Console.WriteLine(“Found ‘{0}’ at position {1}”, m.Value, m.Index);
    }
}


String에 패턴이 여러 번 발생된다면 …
static void Main(string[] args)
{
    Regex r = new Regex(“in”);
    MatchCollection mc = r.Matches(“The King Was in His Counting”);
    for(int i = 0; i < mc.Count; i++)
    {
        Console.WriteLine(“{0}-{1}”, mc[i].Value, mc[i].Index);
    }
}
또는 
static void Main(string[] args)
{
    Regex r = new Regex(“in”);
    string str = “The King Was in His Counting”;
    Match m;
    for(m = r.Match(str); m.Success; m = m.NextMatch())
    {
        Console.WriteLine(“{0}-{1}”, mc.Value, mc.Index);
    }
}
여러 패턴의 인스턴스에 대한 일치 : Regex r = new Regex(“((an)|(in)|(on))”);
여러 패턴의 인스턴스에 대한 일치 : Regex r = new Regex(“Gr(a|e)y”);

Groups
Group클래스는 그룹과 일치하는 하나의 정규식 결과를 표시한다.Match클래스는 GroupCollection 객체를 반환하는 Groups 프로퍼티를 제공한다.
static void Main(string[] args)
{
    Regex r = new Regex(“(i(n))g”);
    string str = “The King Was in His Counting”;
    Match m = r.Match(str);
    GroupCollection gc = m.Groups;

    for(int i = 0; i < gc.Count; i++)
    {
        Group g = gc.[i];
        Console.WriteLine(“Found ‘{0}’ at position {1}”, g.Value, g.Index);
    }
}
Group
Regex q = new Regex(“(?<something>\\w+):(?<anogher>\\w+)”);
Match n = q.Match(“Salary:123456”);
Console.WriteLIne(“{0} = {1}”, n.Groups[“something”].Value, n.Groups[“another”].Value);

//?<another>\\w+ 일치하는 substring을 단어문자만 ‘another’이라는 그룹에 캡처한다.

Captures
msdn.microsoft.com/ko-kr/library/system.text.regularexpressions.capture(VS.95).aspx
.Replace(“string”, “pattern”, “change_string”)
string s = “trailing “;
string e = @”\s+$”;
string r = Regex.Replace(s, e, “”);
>