'아이폰'에 해당되는 글 27건

  1. 2011.10.24 [Portfolio] 아이폰 앱 "나도 작가다 App"
  2. 2011.10.17 [iphone] xcode4에서 앱을 마켓에 등록 하기...삽질 일기 2
  3. 2011.10.14 [iphone] application executable is missing a required architecture armv6 에러 해결법 2
  4. 2011.10.07 [iphone] XMLParser, XMLManager에서 메모리 누수 문제 해결!!!
  5. 2011.10.06 [iphone] 이미지 캐시 라이브러리
  6. 2011.10.06 [iphone] 메모리 관리를 위한 간단한 코딩 습관
  7. 2011.10.05 [iphone] UITableView Scroll Top으로 올리기
  8. 2011.09.30 [iphone] UILabel의 SizeToFit을 여러번 호출할때
  9. 2011.09.27 [iphone] 디버깅상태에서 retain count를 보고 싶을때...
  10. 2011.09.23 [iphone] viewDidAppear 한번만 호출하기
  11. 2011.09.23 [iphone] viewDidAppear 호출이 안될때...
  12. 2011.09.23 [iphone] TableView Custom Cell에 버튼 이벤트 받기 3
  13. 2011.09.22 [iphone] 아이폰에서 ipaddress 얻어오기
  14. 2011.09.21 [iphone] 발전(업그레이드)된 XML Parser 사용하기
  15. 2011.09.19 [iphone] tableviewcell에서 이미지 로딩을 백그라운드로 돌려서 성능 UP
  16. 2011.09.19 [iphone] table selection 안되게 하기 Disable
  17. 2011.09.08 [iphone] plist에 배열 저장/ 읽기
  18. 2011.09.08 [iphone] URL 인코딩 1
  19. 2011.09.08 [iphone] NSUserDefaults 를 이용해서 로그인 정보 저장
  20. 2011.09.07 [iphone] 메모리 접근 오류 해결법(EXC_BAD_ACCESS)
  21. 2011.09.05 [iphone] Lost Focus 하는법, UIView에서 Touch event 받는법
  22. 2011.08.29 [iphone] 경고창 띄우는 법
  23. 2011.08.29 [iphone] synthesize 에서 "_" 언더바를 쓰는 이유
  24. 2011.08.26 [iphone] TextField Foucs 가게하기
  25. 2011.08.24 [iphone] 처음에 Logo Image 나오게하기 (Splash Image)
  26. 2011.08.19 [iphone] TableView 아래로 스크롤시 내용이 하단에 계속 추가 되는 기능 만들기
  27. 2011.08.16 [iphone] TableView에서 긴글을 표시할때 Row 높이를 다이나믹하게 조정하기 5
포트폴리오2011. 10. 24. 11:33


이앱을 만들기 위해서 그전에 칼로리 계산기라던지 hugeboard라는 앱등을 만들어 보았지만 정식 App Store에 올리는 첫 앱입니다.

http://www.1004story.com

사이트를 App으로 만든것인데 서버는 WCF Rest 서비스를 이용하였고 서버에서 XML형식으로 데이터를 보내주면 아이폰에서 파싱해서 사용자들에게 보여주는 앱입니다.

이앱을 만들기 위해서 XmlManager, XmlParser를 직접 만들었으며 현재 인기를 끌고 있는 Facebook, Twitter 앱을 모티브로 해서 만들었습니다. 

구현한 기술
-Refresh to Scroll (위로 올렸다가 내리면 리로딩)
-페이징 (한번에 모든 페이지를 보여주는게 아니라 스크롤이 내리면 10개씩 데이터를 로드)
-Xml Paring (XML 파싱 라이브 러리를 사용한게 아니라 NSParser를 직접 개조해서 제작)
-Twitter,Facebook 연동
-이미지 캐시(Tableview 속도 UP)
-커스텀 테이블 뷰 구현
-달력 컨트롤 사용

등등 입니다.


앱 다운받는곳

http://itunes.apple.com/kr/app/id470488910?ls=1&mt=8



 이외에도 디자인 적용이라든지 로그인 구현이라든지 자잘한게 있지만 스크린샷으로 대체 하겠습니다.














아래는 우리 수석 디자이너 이기백씨가 수정한 이미지 입니다.




 
Posted by 동동(이재동)
iPhone App2011. 10. 17. 14:18

거의 2틀동안 삽질을 했다.

 팀장님 컴퓨터(xocde3)에서는 등록이 잘되지만 내컴퓨터(xcod4)에는 등록할때 엄청난 고난과 역경이 있었다.

그건 바로 인증서 문제였었는데

일단  인증서를 다운받기 위해서는 

http://developer.apple.com/

이 사이트 에서 받을수 있다.

중요한건 폰에 직접 deploy 하는 인증서가 있고 마켓에 올리는 인증서가 따로 있다는것이였다.

그렇다면 어떻게 해야 하는지 차근차근 보자.

일단  직접 폰에 depoly하는 인증서는 위 사이트의  ios provisioning potal에서 받을수 있으며

provisitioning ->development에 가면 다운받을수 있다. 만약 폰에 안들어간다면 profile을 edit해서 해당 device가 check되어 있는지 살펴보자.

이제 마켓에 넣는 인증서를 다운받자. 아까 devlopment 옆에 보면 distibution이라는 항목이 있다 클릭 하자

그쪽에서도  해당 인증서를 생성 및 다운 하자

자 이제 마켓에 올려 보자...(폰에 직접 depoly는 쉬우니까 스킵)

project build setting에 code Signing Identity를 아까 받은 인증서로 바꾼다. 이렇게... 



그다음 xcode 메뉴에서 Product-Archive를 한다.(만약 비활성화라면 기계를 안꼽아서 그런것이다 폰이 있어야 한다.)

그뒤에 Orgaizer- Archives가 나오면 validate하고 submit하면 끝~

아참 중요한건 이때

https://itunesconnect.apple.com/

아이튠즈 connect에 상태가 ready for upload 상태여야 validate와 submit이 가능하다.




 

 
Posted by 동동(이재동)
iPhone App2011. 10. 14. 17:34
으아 1시간 이상을 삽질한거 같다..

iOS5로 업데이트 하면서 배포할려던 나의 앱이 ios5에 맞추어서 다시 수정되었다. ㅠㅠ

그러면서 archvie 하고 vlidation검사를 하는데

application executable is missing a required architecture armv6

이런 에러가 나와서 해결법을 봤더니



이런식으로 distribute와 relase에

모두 다 삭제하고 armv6, armv7을 add하였더니 에러가 안났다... 휴.. 이제 남은 2개 에러를 잡자 ㅠㅠ 
Posted by 동동(이재동)
iPhone App2011. 10. 7. 11:16
으악~

진짜 이거 때문에 얼마나 고생했던지...

나도 작가다 앱에서 xmlParsing하는 부분이 많은데 instruments로 체크 해보니 엄청나게 누수가 일어났었다.

근데 누수에서 xmlParser,xmlManager class쪽에서 누수가 나길레 나는 내가 잘못짰나 싶어서 그부분만 엄청나게 봤었다.

하지만 문제는 그쪽이 아니였다.

NSTableView쪽에서 data를 얻어올때

commentDataArray = [[xmlManager GetXmlArrayDataByData:xmlData elementFile:@"CommentElements.plist"] retain];   

이렇게 retain 해서 저장을 하는데

문제는 delloc이나 viewdidUnload를 거치지 않는것이였다.

내가 만든 view가 화면이 없어지는게 아니라서 호출이 안되나보다... 그러니 계속 retain되니 쌓일수 밖에 그리고 refresh,reload할때도 release가 안되었으니 메모리에 계속 저장하니까 문제가 생길수밖에 없었다.

그래서 날짜를 불러오는부분 즉 reload 할때

-(void) reload

{

    //다른 탭들도 리로딩 하도록 요청한다.     

    [[ReloadManager sharedSingletonClass] SetAllTabReload];

    

    //현재탭은 리로딩 안되도록 한다

    [[ReloadManager sharedSingletonClass] setIsRecentPostReload:NO];

    

    //reload 할때 commentDataArray retain임으로 release한다.

    [commentDataArray release];

    commentDataArray = nil;

    [self prepareReload];

    [self performSelector:@selector(getData) withObject:nil afterDelay:0.5];  

}

저렇게 commmentDataArray를 release하고 nil로 하였다.
 

 

 #pragma mark Data Source Loading / Reloading Methods


- (void)reloadTableViewDataSource{

//  should be calling your tableviews data source model to reload

//  put here just for demo  

    [commentDataArray release];

    commentDataArray = nil;

    [self getData];

_reloading = YES;

}

그리고 tableview를 리로드 하는부분(EGoRefreshTable) delegate에도 테이블을 다시 읽을때마다 release하게 했다.

마지막으로 첨에 읽어오는부분에도 처리 했는데 첨에 읽어오는부분에는 첨에는 commentDataArray가 없기때문에 retainCount로 계산해서 넣었다.

-(void) viewDidAppear:(BOOL)animated

{   

    if([[ReloadManager sharedSingletonClass] isRecentPostReload])

    {

        [[ReloadManager sharedSingletonClass] setIsRecentPostReload:NO];

        [self prepareReload];


        //처음 실행이 아닐경우 이전 날짜로 부터 받아오는경우에는  commentDataArray release되지 않음으로 release해준다.

        if([commentDataArray retainCount] !=0)

        {

            [commentDataArray release];

            commentDataArray = nil;

        }

        [self performSelector:@selector(getData) withObject:nil afterDelay:0.5];  

    }

self.view.frame = self.view.superview.bounds;

}

이런식으로.. 

Posted by 동동(이재동)
iPhone App2011. 10. 6. 15:52
이곳에서 받은 라이브러리인데 잘되는거 같아 포스트 한다.

http://blog.jidolstar.com/723

더 자세한 내용은 나중에 직접 개발해서 올려야지 
Posted by 동동(이재동)
iPhone App2011. 10. 6. 15:41
아이폰 개발은 메모리가 한정되어 있어서 메모리를 항상 관리 하지 않으면 안된다.

아 ~ 그리운 C# ㅠ.ㅠ 가비지 컬렉터 ㅠㅠ

간단한 습관 정리 하자면

1. dealloc는 항상 @synthesize 아래에 놓자.
   @synthesize commentDataArray,commentTableView,loadingFooterIndicator,emptyCommentLabel;


- (void)dealloc { 

    [commentDataArray release];

    [indicator release];

    [commentTableView release];

    [loadingFooterIndicator release];

    

    [_refreshHeaderView release];

    [myAlert release];

    [emptyCommentLabel release];

    [super dealloc];

}

이렇게 놓는다면 비교하기도 쉽고 해제 안한것도 발견하기 쉽다.

2. viewdidload와 viewdidunload는 항상 같이 붙어서 쓸자

-(void) viewDidLoad

[super viewDidLoad];

    

[[ReloadManager sharedSingletonClass] setIsRecentPostReload:YES];


    [self.view addSubview:indicator];

    

    self.loadingFooterIndicator = [[[LoadingFooterIndicator alloc] init] autorelease];

    

    //pull to refresh

    if (_refreshHeaderView == nil) {

        _refreshHeaderView = [[EGORefreshTableHeaderView alloc] initWithFrame:CGRectMake(0.0f, 0.0f - commentTableView.bounds.size.height, commentTableView.frame.size.width, commentTableView.bounds.size.height)];

_refreshHeaderView.delegate = self;

[commentTableView addSubview:_refreshHeaderView];

}    

}


- (void)viewDidUnload {        

[super viewDidUnload]; 

    self.commentDataArray = nil;    

    self.loadingFooterIndicator = nil;    

    self.commentTableView = nil;    

    [_refreshHeaderView release];

    _refreshHeaderView = nil;    

    [indicator release];

    indicator = nil;

    self.emptyCommentLabel = nil;

}


위처럼 붙여서 쓴다면 didload에서 사용한 프로퍼티나 변수를 보기 쉽고 릴리즈를 할수 있다.

  
3 viewdidload에서 사용한것은 항상 did unload에서 relase와 nil로 정해줄것
   위에 보면 알겠지만 프로퍼티로 정의해둔것은 viewDidUnload할때  nil처리하면 알아서 relase되지만
   프로퍼티가 아닌 그냥 전역 변수는
       
[indicator release];

    indicator = nil;

  이렇게 한번 release해주고 nil처리 해줘야 한다.
 


4. IBOulet는 프로퍼티로도 만들자.
   xcode4에서는 워닝이 안나지만 xcode3는 워닝이 난다.


 

 

 

 




 
Posted by 동동(이재동)
iPhone App2011. 10. 5. 10:52


머 윈폰도 같지만 그냥 까먹까바 올린다.
   
[
commentTableView setContentOffset:CGPointMake(0, 0) animated:NO]; //table 스크롤을 상단에 올린다.

Posted by 동동(이재동)
iPhone App2011. 9. 30. 18:38

멀티라인이나 싱글라인에서

UIlabel SizeToFit을 하게되면 그글자에 맞추어서 크기가 변경된다.

근데 한번 길이를 줄여서 label이 짧아졌는데 다시 그 label에 긴글을 들어 왔을때에는 크기를 다시 초기화를 해줘야 한다.

그래서 데이터가 다이나믹 한 Label을 쓸경우

  subjectDetailLabel.frame = CGRectMake(46, 68, 271, 60);

[subjectDetailLabel sizeToFit];


이렇게 초기 frame값을 얻어와서 sizetofit을 호출하기전에 초기화를 해버리자.
Posted by 동동(이재동)
iPhone App2011. 9. 27. 15:54
XCode의 디버거에서는 변수의 retain count를 볼 수가 없어서 불편한데요, 디버깅 중에 볼 수 있는 방법이 없지는 않습니다. gdb의 디버깅 콘솔을 띄워서 다음과 같이 입력하면 theObj의 retain count 가 출력됩니다.

print (unsigned int)[theObj retainCount]
Posted by 동동(이재동)
iPhone App2011. 9. 23. 15:26
기본적으로 view를 로드 할때마다 부르는데

용도를 view가 모두 로드된뒤에 어떤작업을 수행하기 위한 용도로 쓴다면 한번만 호출했으면 한다.

예를들면 tableview같은곳~

인터넷 찾아보니..아주 간단하다.. ㅋㅋ
BOOL firstTime;

in the .m file:
-(void)viewDidLoad {
   NSLog(@"viewDidLoad actually fired");
   //...
   firstTime = YES;
}
-(void)viewDidAppear {
   //...
   if(firstTime){
      //show it
      firstTime = NO;
   }
}
 
참고 : http://stackoverflow.com/questions/2259977/how-can-i-call-the-viewdidappear-only-one-time 
Posted by 동동(이재동)
iPhone App2011. 9. 23. 15:07
viewDidappear는 navigation Conroller일때 호출이 된다.

viewdidload를 할경우에는 프로그램이 실행할때 호출되어서 로딩이 길어진다.

그래서 view가 여러개 있고 클릭했을때  어떤작업?(data를 불러오는작업) 이 일어나게 해서 퍼포먼스를 향상 시키기로 했다.

-(IBAction) menuSelected:(id)sender

{

UIButton* menu = (UIButton*)sender;

if(menu.selected == YES)

return;

    self.giftButton.selected = NO;

    self.recentButton.selected = NO;

    self.myButton.selected = NO;

    self.popularButton.selected = NO;

    

menu.selected = YES;

UIViewController* vc = nil;

if(sender == recentButton)

{

vc = [menuViewControllers objectAtIndex:kRecentPostsIndex];

}

else if(sender == popularButton)

{

vc = [menuViewControllers objectAtIndex:kMostPopularPostsIndex];

}

else if(sender == myButton)

{

vc = [menuViewControllers objectAtIndex:kMyPostingsIndex];

}

else if(sender == giftButton)

{

vc = [menuViewControllers objectAtIndex:kTodayGiftIndex];

}

for(UIView* sv in contentView.subviews)

{

[sv removeFromSuperview];

}


[contentView addSubview:vc.view];

    [vc viewDidAppear:FALSE];

    

}
이것은 메뉴를 선택했을시 해당 하는 뷰를 add하는 메소드이다.

[vc viewDidAppear:FALSE];

이것을 해주지 않았다면 viewDidappear는 호출되지 않는다. 

view를 add한후 viewdidappear를 사용하고 싶을때 사용하자
 
  

참고 : http://stackoverflow.com/questions/2335722/problem-with-iphone-shakes-viewdidappear-isnt-called-when-loading-viewcontrolle 
Posted by 동동(이재동)
iPhone App2011. 9. 23. 10:42
여러가지 방법을 해보았다.

물론 Custom Cell Class에서 Action을 걸어서 하는 방법이 있지만 나는 TableView가 있는 클래스의 Data Array를 사용해야만 했기때문에

TableView가 있는 Class에서 Action을 받고 싶었다. (이것도 여러가지 방법으로 해봄)

일단 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{   

    BoardCustomCell *cell = (BoardCustomCell *)[tableView dequeueReusableCellWithIdentifier:BoardCustomCellIdentifier];

    

    // NSUInteger row = indexPath.row;

    

if(cell == nil)

{

        cell = [BoardCustomCell cellWithNib];

}        

    

    NSMutableDictionary* commentData = (NSMutableDictionary*)[commentDataArray objectAtIndex:indexPath.row];    

    cell.contentLabel.text = [commentData objectForKey:@"CmtContent"];

    cell.memberNameLabel.text = [commentData objectForKey:@"MemberName"];    

    cell.dateLabel.text = [commentData objectForKey:@"CreateDate"];

    cell.memberLevelLabel.text = [commentData objectForKey:@"PntSumLv"];

    cell.memberPointLabel.text = [commentData objectForKey:@"ReCmdCount"];


    

    UIImage *image = [UIImage   imageNamed:@"delbtn.png"];    

    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];

    CGRect frame = CGRectMake(0.0, 0.0, image.size.width, image.size.height);

    button.frame = frame;

    [button setBackgroundImage:image forState:UIControlStateNormal];    

    [button addTarget:self action:@selector(checkButtonTapped:event:)  forControlEvents:UIControlEventTouchUpInside];    

    cell.accessoryView = button;


아래처럼 cell.accesooryView에 버튼 생성해서 넣었다.  

액션 셀렉터에서

- (void)checkButtonTapped:(id)sender event:(id)event

{

    NSSet *touches = [event allTouches];

    UITouch *touch = [touches anyObject];

    CGPoint currentTouchPosition = [touch locationInView:commentTableView];

    NSIndexPath *indexPath = [commentTableView indexPathForRowAtPoint: currentTouchPosition];

    NSMutableDictionary* commentData = (NSMutableDictionary*)[commentDataArray objectAtIndex:indexPath.row];   

    

    NSString* cmtIdx= [commentData objectForKey:@"CmtIdx"];


    [self performSelector:@selector(sendSympathy:) withObject:cmtIdx afterDelay:0.5];

}


이렇게 구현을 했다.
 

참고 :http://www.edumobile.org/iphone/iphone-programming-tutorials/impliment-a-custom-accessory-view-for-your-uitableview-in-iphone/
 
Posted by 동동(이재동)
iPhone App2011. 9. 22. 16:25

http://blog.zachwaugh.com/post/309927273/programmatically-retrieving-ip-address-of-iphone

근데 에뮬레이터에서는 받아오지 못한다.

Posted by 동동(이재동)
iPhone App2011. 9. 21. 19:33

일단 이전에 만든 XML은 진짜 기본적인 Parser인거 같다... 내가 실제로 XML Parser를 사용함으로써 수많게 유용하고 유연하게

바꾸었다. 어떤 XML이 들어와도 읽을수 있게(이건 오버인가?..)

일단 발전된 상황이라면 모든 XML을 Dictionary로 관리하기 때문에 유연하게 바뀌었다.

XML Parser에서 initWithContentsOfURL을 이용하면 네트워크가 안될시나 URL이 잘못되면 어떠한 예외를 던지지 못하고 멈추는 현상이 있어서

일단 나는 파싱하기전에 그 URL이 XML을 정상적으로 리턴하는지 검증하는것이 필요 하였다.

원리는 이렇다.

일단 XML받는부분을 Background에서 실행한다.

[self performSelector:@selector(getTime) withObject:nil];


그리고 아래 예제처럼하였다.


- (void) getTime

{

NSString *serverIP = [[NSUserDefaults standardUserDefaults] objectForKey:@"ServerIP"];

NSURL* url =[NSURL URLWithString:[[NSString stringWithFormat:TimeElementsURL,serverIP]stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

  

XmlManager* xmlManager= [[XmlManager alloc] init];

  

NSData* xmlData = [xmlManager GetXmlData:url isPostData:NO];

  

if(xmlData != nil) {

NSMutableDictionary *xmlDict= [xmlManager GetXmlDictDataByData:xmlData elementFile:@"TimeElements.plist"];

NSUserDefaults *timeData = [NSUserDefaults standardUserDefaults];

[timeData setObject:xmlDict forKey:@"TimeData"];

[timeData synchronize];

  

//시간 설정

currentTime = [[xmlDict objectForKey:@"TimeSec"] intValue];

int secs = currentTime % 60;

int mins = (currentTime % 3600) / 60;

int hours = currentTime / 3600;

timeRemainLabel.text = [NSString stringWithFormat:@"%.2d:%.2d:%.2d",hours, mins, secs];

  

}

else {

NSLog(@"time data 얻기 실패");

}

  

  

[xmlManager release];

}

소스는 거창하지만 실제로 보면

NSData* xmlData = [xmlManager GetXmlData:url isPostData:NO];  


이부분을 보면 된다. 내가 구현한 xmlManager는 파일첨부 할것이다.

저렇게 일단 XML을 파싱하기전에 파싱데이터를 가져온다.

만약 저기서 data를 못받으면(data == nil) 실패했다고 말해준다.

이것이 바로 검증인것이다.
실패했는지 성공했는지 결과를 알수 있다는것이다.

성공하면 이렇게 파싱한다.
NSMutableDictionary *xmlDict= [xmlManager GetXmlDictDataByData:xmlData elementFile:@"TimeElements.plist"];
 
그리고 elementFile은 plist를 만들어서



 
이렇게 만든다. 

NSManager에 GetXmlData 소스는 이렇다.
-(NSData*)GetXmlData:(NSURL*) url isPostData:(BOOL) isPost

{

    NSMutableURLRequest* feedRequest = [NSMutableURLRequest requestWithURL:url cachePolicy: NSURLRequestUseProtocolCachePolicy timeoutInterval:10];

    if(isPost == YES)

    {

        [feedRequest setHTTPMethod:@"POST"];

    }

    NSError* theError = nil;

NSData* xmlData = [NSURLConnection sendSynchronousRequest:feedRequest returningResponse:nil error:&theError];     

//    NSString *str = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];     //확인용    


    if(theError != nil || xmlData ==nil)

    {        

        //네트워크가 잘못됬거나 data 가져 오지 못했을 경우 nil return

        return nil

    }

    else

    {

        return xmlData;

    }


2011년 10월 12일  추가

NSXmlparser버그로 인해서 첫글자가 숫자일경우 짤려서 foundCharacters 두번 호출되는 버그가 있었다.

Xml에 들어온글중에 원래 xml의 element안에 있는글이

"
1004 story 들어오기. 나도 글을 쓰고 싶을 뿐이다 ㅠㅠ"

라는 글이였는데 
 

"에 들어오기. 나도 글을 쓰고 싶을 뿐이다 ㅠㅠ"

만 나오는것이였다 보니까 1004 story라는 글이 짤려 있었다.

그래서 보니 첫글자가 숫자가 들어가니 아래 로그 처럼 나뉘어서 두번에 걸쳐서 foundCharacters delegate가 호출 되었다.

 

2011-10-12 11:09:01.447 나도 작가다[1151:207] CmtContent

2011-10-12 11:09:01.447 나도 작가다[1151:207] 1004 story  , CmtContent

2011-10-12 11:09:01.448 나도 작가다[1151:207] count = 2, index= 0 

2011-10-12 11:09:01.448 나도 작가다[1151:207] 들어오기. 나도 글을 쓰고 싶을 뿐이다 ㅠㅠ , CmtContent

그래서 아래처럼 수정하였다.

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string

    //trim 쓰자면 이걸 쓰고 안하면 그냥 string 값을 넣어도 된다.

    NSCharacterSet *characterSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];

    NSString *trimmedValue = [string stringByTrimmingCharactersInSet:characterSet];

    

     if([trimmedValue length] == 0)

    {

        return;    

    }

    

    id element = [elementStack lastObject];    

    

    if([element isKindOfClass:[NSString class]])

    {

        NSUInteger count = [elementStack count];

        NSUInteger index = count -2;

        id parentElement = [elementStack objectAtIndex:index];                               

        

        NSMutableDictionary *dataInfoDict = (NSMutableDictionary*)parentElement;        

        

        //NSXmlparser버그로 인해서 첫글자가 숫자일경우 짤려서 foundCharacters 두번 호출된다.

        if([element isEqualToString:@"CmtContent"])

        {

            if([[dataInfoDict allKeys] containsObject:element])

            {                

                NSString* previousString = (NSString*)[dataInfoDict objectForKey:element];

                trimmedValue =[previousString stringByAppendingString:trimmedValue]; 

            }

        }

        

        [dataInfoDict setObject:trimmedValue forKey:element]; 

    }    

}


요약하자면 이전에 dictionary를 검색해서 이미 값이 있으면 이전 값과 현재 값을 합쳐서
저장한다.

만약 이전값이 없으면 무시되니깐 정상적으로 작동한다.
 
 
최신 xmlParser는 올려놓겠다

 

Posted by 동동(이재동)
iPhone App2011. 9. 19. 10:55

이렇게 커스텀 셀을 만든후


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

BoardCustomCell *cell = (BoardCustomCell *)[tableView dequeueReusableCellWithIdentifier:BoardCustomCellIdentifier];

  

// NSUInteger row = indexPath.row;

  

if(cell == nil)

{

cell = [BoardCustomCell cellWithNib];

}

  

NSMutableDictionary* commentData = [commentDataArray objectAtIndex:indexPath.row];

cell.contentLabel.text = [commentData objectForKey:@"CmtContent"];

cell.memberNameLabel.text = [commentData objectForKey:@"MemberName"];

cell.dateLabel.text = [commentData objectForKey:@"CreateDate"];

cell.memberLevelLabel.text = [commentData objectForKey:@"PntSumLv"];

cell.memberPointLabel.text = [commentData objectForKey:@"ReCmdCount"];

  

//image 나중에 주소를 plist 넣자

NSString* imageUrl= [NSString stringWithFormat:@"http://주소/%@",[commentData objectForKey:@"MemberPhoto"]];

  

if ([commentData objectForKey:@"MemberPhoto"] == nil)

{

imageUrl= [NSString stringWithFormat:@"http://주소/default_profileImg_small.gif"];

}

  

// UIImage* memberPhotoImage= [[UIImage alloc]initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imageUrl]]];

// UIImage* memberPhotoImage= [[UIImage alloc]initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imageUrl]]];

  

[cell performSelectorInBackground:@selector(setImageUrl:) withObject:imageUrl];

// NSURL *url = [NSURL URLWithString:imageUrl];

// NSData *data = [NSData dataWithContentsOfURL:url];

// UIImage *memberPhotoImage = [[UIImage alloc] initWithData:data];

//

// [cell.memberPhotoImage setImage:memberPhotoImage];

// [memberPhotoImage release];

  

return cell;

}


주석 처리한 부분으로 이미지를 처리 했는데 느려서

[cell performSelectorInBackground:@selector(setImageUrl:) withObject:imageUrl];

이렇게 cell에서 이미지 처리를 백그라운드로 돌렸다.

cell 에서 구현한 소스는 이렇다.

-(void) setImageUrl:(NSString *)urlString

{

NSAutoreleasePool* pool = [NSAutoreleasePool new];

  

NSURL *url = [NSURL URLWithString:urlString];

NSData *data = [NSData dataWithContentsOfURL:url];

UIImage *img = [[[UIImage alloc] initWithData:data] autorelease];

  

[self.memberPhotoImage setImage:img];

[pool release];

}

Posted by 동동(이재동)
iPhone App2011. 9. 19. 10:48

//table 셀렉트 안되게

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath{

return nil;

}

Posted by 동동(이재동)
iPhone App2011. 9. 8. 14:10

먼저 프로젝트에 plist파일을 만들고 이런식으로 추가한다.

201109081408.jpg

추가후

  NSString *path = [[NSBundle mainBundle] bundlePath];

NSString *finalPath = [path stringByAppendingPathComponent:@"LogInElements.plist"];

NSMutableDictionary *namesPlist = [[NSMutableDictionary alloc] initWithContentsOfFile:finalPath];

NSMutableArray* elementNameArray = (NSMutableArray*)[namesPlist objectForKey:@"names"];


이렇게 읽어오면 array 가져올수 있다 편하다!!
Posted by 동동(이재동)
iPhone App2011. 9. 8. 11:20

로그인 작업을 할때 특수문자나 한글이 들어갔을때 에러가 나지 않게 하기 위해서는 URL을 인코딩해야 한다.   

NSString *urlString =[NSString stringWithFormat:@"http://주소/Member/MemberSelect?id=%@&pw=%@",_userID.text,_userPW.text];

  

NSString *escapedUrl = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

  

NSURL *XMLURL =[NSURL URLWithString:escapedUrl];


참조 : http://www.digipine.com/programming/6119

Posted by 동동(이재동)
iPhone App2011. 9. 8. 11:16

로그인 정보를 그냥 아이솔레이티드처럼 저장할려 했더니 이런게 존재했다. 정말 간편하게 저장가능하다.

이런식으로 string 및 object형태로 저장가능하다.

나는 NSMutableDictionary에 로그인 정보들을 저장해서 바로 넣어버렸다.

- (void) saveLoginData:(NSMutableDictionary*)data

{

NSUserDefaults *UserloginData = [NSUserDefaults standardUserDefaults];

[UserloginData setObject:data forKey:@"LoginInfoData"];

[UserloginData synchronize];

NSLog(@"Activated = %@",[(NSMutableDictionary*)[UserloginData objectForKey:@"LoginInfoData"] objectForKey:@"Admin"]);

}


간단하다.


Posted by 동동(이재동)
iPhone App2011. 9. 7. 14:30

이오류는 거의 메모리 오류다 일단 나는 2번 dealloc부터 해제 하니깐 메모리 에러를 잡았다.

1. 디버깅 스택을 확인해서 오류난 지점을 찾아라

- 사용자 코드가 나타나지 않을때는 dealloc 확인(네이게이션 컨트롤러에서 팝업될때 많이 발생)

2. dealloc 부터 디버깅해라 !!!

- nil 이 아니고 할당되지 않은 인스턴스에 release 메시지를 날리면 EXC_BAD_ACCESS

3. 부모 컨트롤러에서 값을 받아올때는 retain 하라 !!

- retain 안하면 그냥 주소값만 가져와서 부모에서 release 해버리면 잘못된 접근이 된다.

- 맘편히 프로퍼티로 할당하면 하자. self.param = input_param; 하면 내부적으로 기존것 release, 새것 retain 한다.

4. NSZombiesEnabled 를 활용하자

Posted by 동동(이재동)
iPhone App2011. 9. 5. 20:46

일단 내가 하고 싶던건 로그인 페이지에서 텍스트 필드에 포커스가 가면 키보드가 뜨고

그외에 곳을 터치하면 키보드가 닫기는 그런 구현을 하고 싶었다.

- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event


{

[_userID resignFirstResponder];

[_userPW resignFirstResponder];

}

이렇게 touchesBegan 델리게이트를 이용해서 View를 터치할경우

resingFirstResponder로 focus를 잃게 했다.

Posted by 동동(이재동)
iPhone App2011. 8. 29. 17:19

   UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"login" message:@"메세지" delegate:self cancelButtonTitle:@"확인" otherButtonTitles:@"취소", nil];

[alert show];

[alert release];


참고 : http://blowmj.tistory.com/entry/IPhoneUIAlertView경고창-띄우는-방법과-경고창이-여러개일-때-이벤트-구별하는-방법

Posted by 동동(이재동)
iPhone App2011. 8. 29. 14:47

synthesize 팁

외부에서 접근하는 프로퍼티 이름과 내부의 변수 이름을 항상 일치시켜야 할까 ? 그렇지는 않다. 많은 개발자가 다음과 같은 기법을 사용한다.

01: // 헤더

02: @interface AccessorTest2 : NSObject {

03: BOOL _enable;

04: }

05: @property (readwrite,assign) BOOL enable;

06: @end

07:

08: // 구현

09: @implementation AccessorTest2

10:

11: @synthesize enable = _enable;

12:

13: @end

즉 실제 내부 변수를 언더바(_) 문자로 시작하게 선언한다. 그리고 외부에서 접근할 때는 언더바를 제거한 문자로 접근하도록 하는 것이다. 이렇게 해서 내부에서 접근할 때와 외부에서 접근할 때의 차이를 쉽게 구분하도록 한다.

self.enable = YES; // 접근자를 통한 설정

_enable = YES; // 객체 내부에서 접근

위 코드와 같이 접근자로 접근하는 것과 내부에서 접근하는 경우를 확연히 구분할 수 있다. 이 때 synthesize 에 = 가 사용된 것은 enable 이라는 프로퍼티가 _enable 이라는 멤버 변수를 사용한다는 것을 알리기 위한것이다.

출처 : http://blog.messfilm.com/?p=84

외부와 내부에서 접근할때를 구분은 왜 하는것일까? 사실 c#때도 private와 public를 사용해서 좀더 캡슐화에 가깝게 객체지향적으로 짠다.

이것도 그런것일까... 근데 이건 public은 원래 있는것이고 추가적으로 private를 더 만드는것이라 좀 애매하다. 아직 갈길이 멀구나.

Posted by 동동(이재동)
iPhone App2011. 8. 26. 16:44

나도 작가다 앱에서 로그인부분을 만들기 위해 페이스 북 로그인을 모방해 봤다.

페이스북은 항상 키패드가 떠 있는걸 보니 첫 id 입력 부분 textfiled에 focus를 강제로 두고 시작 했다.

방법은 간단하다.

- (void)viewDidLoad

{

[super viewDidLoad];

// Do any additional setup after loading the view from its nib.

[[self userID] becomeFirstResponder];

}


첫 로드 부분에 userID(이게 텍스트 필드랑 연결된 Outlet) 포커스를 가게 했다.


Posted by 동동(이재동)
iPhone App2011. 8. 24. 13:54

간단하다...

그냥 프로젝트에 Default.png 파일을 넣으면 자동으로 해준다.

참고 : http://ekle.us/index.php/2008/10/iphone-application-splash-screens

Posted by 동동(이재동)
iPhone App2011. 8. 19. 17:19

으아~~

쓴거 다 날라갔다 힘들게 썻는데

참고한곳 : http://blog.keyoptions.co/tableview-with-automatic-load-more

참조한곳 소스: 


내가 수정한 소스 



Posted by 동동(이재동)
iPhone App2011. 8. 16. 17:57

TableView를 이용해서 SNS를 개발 하기위해 선두지점에 있는 Facebook 앱을 보았다.


201108161711.jpg

이렇게 Label이 길수록 TableView cell row가 길게 나왔다.

이렇게 할려면 글을 길이를 계산해서 row의 높이를 계산해야 한다.

#define FONT_SIZE 14.0f

#define CELL_CONTENT_WIDTH 320.0f

#define CELL_CONTENT_MARGIN 10.0f


일단 사이즈를 계산하기 위해 고정적인 정보를 정의 했다.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;

{

NSString *text = [items objectAtIndex:[indexPath row]];

  

CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);

  

CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];

  

CGFloat height = MAX(size.height, 44.0f);

  

return height + (CELL_CONTENT_MARGIN * 2);

}


그리고 heightForRowIndexPath 델리게이트를 이용해서 글의 길이에 따라 cell의 높이를 변화시켰다.items 에는 tableview itemsource가 담겨 있다.
자 이제 실제 label을 조정해 보자.

- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

UITableViewCell *cell;

UILabel *label = nil;

  

cell = [tv dequeueReusableCellWithIdentifier:@"Cell"];

if (cell == nil)

{

cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"Cell"] autorelease];

  

label = [[UILabel alloc] initWithFrame:CGRectZero];

  

[label setLineBreakMode:UILineBreakModeWordWrap];

[label setMinimumFontSize:FONT_SIZE];

[label setNumberOfLines:0];

[label setFont:[UIFont systemFontOfSize:FONT_SIZE]];

[label setTag:1];

  

// [[label layer] setBorderWidth:2.0f];

  

[[cell contentView] addSubview:label];

  

}

NSString *text = [items objectAtIndex:[indexPath row]];

  

CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);

  

CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];

  

if (!label)

label = (UILabel*)[cell viewWithTag:1];

  

[label setText:text];

[label setFrame:CGRectMake(CELL_CONTENT_MARGIN, CELL_CONTENT_MARGIN, CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), MAX(size.height, 44.0f))];

  

return cell;


}


빈 label을 만들어서 add하는 형식이다. 그리고 label의 크기를 이렇게 유동적으로 변형시킨다.

[label setFrame:CGRectMake(CELL_CONTENT_MARGIN, CELL_CONTENT_MARGIN, CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), MAX(size.height, 44.0f))];


이렇게 하면


201108161748.jpg


이렇게 다이나믹하게 row의 높이가 변한다.


참고 : http://www.cimgf.com/2009/09/23/uitableviewcell-dynamic-height/


하지만 나는 코드상에서 label을 만들어서 하지 않고 ib에서 만들어서 적용할려고 했다. 그래야 쉽지 ㅋㅋ


내가 응용한 코드는 다음과 같다.


//table height label 크기에 따라 변환

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;

{

HugeBoardData* hd = [boardData objectAtIndex:indexPath.row];


CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);

  

CGSize size = [hd.title sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];

  

CGFloat height = MAX(size.height, 44.0f);

  

return height + (CELL_CONTENT_MARGIN * 2);

}


size에 보면 hd.title이 있다. title의 크기를 기준으로 높이를 계산해서 반환한다.


그리고 크기를 내크기에 맞게 변환했다.


#define FONT_SIZE 14.0f

#define CELL_CONTENT_WIDTH 140.0f

#define CELL_CONTENT_MARGIN 10.0f



마지막으로 cellForRowAtIndexPath 델리게이트는

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {  

  

HugeBoardCell *cell = (HugeBoardCell *)[tableView dequeueReusableCellWithIdentifier:HugeBoardCellIdentifier];

  

if (cell == nil) {   

cell = [HugeBoardCell cellWithNib];

[cell.titleLabel setMinimumFontSize:FONT_SIZE];

[cell.titleLabel setLineBreakMode:UILineBreakModeWordWrap];

[cell.titleLabel setNumberOfLines:0];

[cell.titleLabel setFont:[UIFont systemFontOfSize:FONT_SIZE]];

[cell.titleLabel setTag:1];

}

  

HugeBoardData* hd = [boardData objectAtIndex:indexPath.row];

CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);

  

CGSize size = [hd.title sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];

  


cell.titleLabel.text = [NSString stringWithFormat:@"%@", hd.title];

[cell.titleLabel setFrame:CGRectMake(CELL_CONTENT_MARGIN+40, CELL_CONTENT_MARGIN, CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), MAX(size.height, 44.0f))];

cell.idxLabel.text= [NSString stringWithFormat:@"%@ : ", hd.idx];

return cell;

}


이렇게 구현했다. 달라진게 있다면 현재 titleLabel은 custom cell의 ib에서 연결된 label이다.즉 behind code에서 처리하지 않고 ib에서 이미 만든값의 크기를 다이나믹하게 변경하였다.
결과는
201108161755.jpg
맨하단에 보면 저렇게 긴글도 제대로 표시해주고 있다.

201108161756.jpg
현재 table의 cell은 이렇게 되어있다. 즉 저기 content라고 써있는 label의 높이를 변형시켰다.
이렇게 약간 페이스북에 가까이 가는거 같다.
Posted by 동동(이재동)