2014년 5월 22일 목요일

[iOS] Poster Scroll View를 만들어 봅니다.

영화관 앱에서 포스터를 옆으로 넘길 때, 현재 페이지의 이미지와, 다음페이지의 이미지가 약간 겹처서 넘어갑니다.
Yahoo 날씨 앱에서도 각 페이지를 양 옆으로 넘길 때, 이미지가 겹쳐서 넘어가게 됩니다.

이것을 스크롤 뷰를 이용해서 구현해 보도록 하겠습니다.

1. 전체 구현방법

 스크롤 뷰에 현재 frame크기의 각 페이지로 커스텀 뷰(DBUMoviePosterView)를 추가하고, 화면이 이동할 때, 커스텀 뷰에서 이미지의 위치를 조정해주게 된다.
 이 커스텀 뷰에서 추가된 내부 뷰가 이동할 때, 배경이 바깥 부분으로 나가지 않도록 레이어의 masksToBound도 설정해 준다.
 오른쪽에서 왼쪽으로 다음페이지의 이미지가 나올 때는, 현재 위치를 계산해서, 중간에서 오른쪽으로 이동하도록 하고,
 왼쪽에서 오른쪽으로 이전 페이지의 이미지가 나올 때, 중간에서 왼쪽으로 이동하도록 한다.

2. 소스 구현

 - DBUScrollView
source code
@interface DBUScollView()
@property (nonatomic, strong) NSMutableArray *posters;
@end

@implementation DBUScollView
- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        self.delegate = self;
    }
    return self;
}
- (NSMutableArray *)posters
{
    if (_posters == nil) {
        _posters = [NSMutableArray array];
    }
    return _posters;
}
- (void)addPoster:(UIImage *)image
{
    CGSize size = self.frame.size;
    //포스터 전체 개수
    NSUInteger posterTotalCount = [self.posters count];
    //content 영역 설정
    self.contentSize = CGSizeMake(size.width * (posterTotalCount+1), size.height);
    // 포스터 뷰 생성 및 추가
    DBUMoviePosterView *posterView = [[DBUMoviePosterView alloc] initWithFrame:CGRectMake(size.width*(posterTotalCount), 0, size.width, size.height)];
    UIImageView *imageView = [[UIImageView alloc] initWithFrame:posterView.bounds];
    imageView.image = image;
    [posterView addView:imageView];
    [self addSubview:posterView];

    //위치 이동을 위해서, Array로 보관
    [self.posters addObject:posterView];
}

#pragma mark - UIScrollViewDelegate
- (void)posterImagePosition:(NSInteger)posterIndex point:(CGPoint)point
{
    if (posterIndex < 0 || posterIndex >= self.posters.count) {
        return; //페이지 수를 벗어난 것이면, 무시한다.
    }
    DBUMoviePosterView *posterView = (DBUMoviePosterView *)self.posters[posterIndex];
    if (posterView == nil) return;
    [posterView moveViewPosition:point]; //각 포스터 뷰에서 내부 뷰를 이동시킨다.
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    //현재 페이지를 계산해서, 연재와 다음 것만 움직이도록 한다.
    NSUInteger currentPage = scrollView.contentOffset.x / scrollView.frame.size.width;
    //계산은 각 포스터 뷰에서 계산한다.
    [self posterImagePosition:currentPage point:scrollView.contentOffset];
    [self posterImagePosition:currentPage+1 point:scrollView.contentOffset];
}
@end



- DBUMoviePosterView
source code
#import "DBUMoviePosterView.h"
@interface DBUMoviePosterView()
{
    UIView *_view;
}
@end

@implementation DBUMoviePosterView
- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        self.layer.masksToBounds = YES;//
    }
    return self;
}
- (void) addView:(UIView *)view
{
    if (_view != nil) {
        [_view removeFromSuperview];
        _view = nil;
    }
    _view = view;
    [self addSubview:view];
}
- (void) moveViewPosition:(CGPoint)point
{
        CGFloat width = self.frame.size.width;
    CGFloat height = self.frame.size.height;
    CGFloat x = point.x - self.frame.origin.x;
    
    if (x > -width && x < width) {
        //현재 위치와 비교한 값의 절반을 x좌표로 한다.
        _view.frame = CGRectMake(x/2, point.y, width, height);
    }
}
- (void) moveViewPositionToInitial
{
    //(0,0)으로 원위치 시킴.
    [self moveViewPosition:CGPointMake(0, 0)];
}


3. 결과물




[iOS] sizeWithFont를 대체하는 함수 사용법

iOS7이전에는 NSString이 특정 가로 크기에서 줄바꿈 등을 통해서, 높이가 얼마나 되는지 알아보기 위해서는 sizeWithFont:constrainedToSize를 사용하였는데, 7.0에서는 Deprecated가 되어서 변경해야 합니다.
iOS7에서는 font뿐만 아니라, 다른 Attribute들도 높이를 구할 때 필요하므로 font만 참고하는 것이 아니라, attributes라고 NSDictionary를 받아서 구하게 됩니다.

sizeWithFont:constrainedToSize (Deprecated)
    //특정 영역 (268, 4000)의 크기에서 myString에 있는 글의 높이를 iOS6에서 구하는 방법
    UIFont *font = [UIFont fontWithName:@"HelveticaNeue-Light" size:10];
    CGSize aboutSize = [myString sizeWithFont:font constrainedToSize:CGSizeMake(268, 4000)];


Xcode5에서는 boundingRectWithSize:options:attributes:context:를 사용하라고 나옵니다.

    //폰트가 따로 정리가 되어 있지 않는 경우는
    UIFont *font = [UIFont fontWithName:@"HelveticaNeue-Light" size:10];
    CGRect aboutRect = [myString //높이를 구할 NSString 
                          boundingRectWithSize:CGSizeMake(268, CGFLOAT_MAX) 
                                       options:NSStringDrawingUsesLineFragmentOrigin 
                                    attributes:@{NSFontAttributeName:font} 
                                       context:nil];

만약 일반 NSString이 아니고, NSAttributedString을 사용하고 있으면, attributes가 없는 함수를 사용하면 됩니다.

    //폰트가 따로 정리가 되어 있지 않는 경우는
    UIFont *font = [UIFont fontWithName:@"HelveticaNeue-Light" size:10];
    NSAttributedString *myAttributedString = [[NSAttributedString alloc] initWithString:myString
               
    CGRect aboutRect = [myAttributedString //높이를 구할 NSAttributedString
                         boundingRectWithSize:CGSizeMake(268, CGFLOAT_MAX) 
                                      options:NSStringDrawingUsesLineFragmentOrigin
                                      context:nil];                                                              

정리해 둡니다.

2014년 5월 17일 토요일

[iOS] Facebook에 글과 이미지, 링크 등록하기.

iOS6 부터 Facebook에 글을 올릴 수 있는 방법을 제공하고 있습니다.
내부 동작방식은 Twitter에 올리는 것과 동일한 방법에 서비스 타입만 변경하면 됩니다.

Twitter에 글 올리기 

위의 트위터에 글 올리기에 설명한 것과 같이, 이미지와 URL을 추가할 수 있습니다.

 source code
- (IBAction)uploadToFacebook:(UIBarButtonItem *)sender {
    if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {
        SLComposeViewController *composer = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
        [composer setInitialText:@"Initial Text for Facebook :)"];//초기 메시지.
        [composer addImage:self.uploadImage]; //추가할 이미지
        [composer addURL:[NSURL URLWithString:APP_URL_IN_ITUNES]];//추가할 URL
        composer.completionHandler = ^(SLComposeViewControllerResult result){
            switch(result) {
                    //  This means the user cancelled without sending the Tweet
                case SLComposeViewControllerResultCancelled:
                    break;
                    //  This means the user hit 'Send'
                case SLComposeViewControllerResultDone:
                    break;
            }
        };
        [self presentViewController:composer animated:YES completion:^{
            //NSLog(@"present completed");
        }];
    }else{
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Sorry"
                                                            message:@"You can't upload this page to Facebook right now, make sure your device has an internet connection and you have at least one Facebook account setup"
                                                           delegate:self cancelButtonTitle:@"OK"
                                                  otherButtonTitles: nil];
        [alertView show];
    }
}

페이스북에 대한 연결이 되어 있지 않은 경우, 아래와 비슷하게 업로드를 할 수 없다고 알려줘야 합니다.
Upload가 불가능함을 알림.
만약, 아이디가 설정이 되어 있으면, 아래와 같이 Facebook Composer가 표시가 됩니다.
페이스북 타입의 SLComposeViewController
이미지를 어느 앨범에 올릴지, 현재 위치를 추가할지, 공개를 어느 범위까지 할지 표시합니다.
만약, 이 화면에서 Post를 했는데, 인터넷 연결이 안되어 있는 경우, 아래와 같이 표시가 됩니다.

Facebook에 Upload하지 못할 경우 표시화면



참고:
- Integrating Twitter and Facebook into iOS7 Applications
- Mobile and Social Network Technology - Tutorial: How to use inbuilt Facebook/Twitter API in iOS6
- iOS Programming 101: Integrate Twitter and Facebook Sharing in Your App.
- Open Source Control For Creating SLComposeViewController Type Views For Any Social Network



2014년 5월 15일 목요일

[iOS6] Twitter에 이미지와 링크 올리기

iOS6에서 트위터에 이미지와 글을 올릴 수 있는 방법을 자체 Framework으로 제공하고 있습니다.
Social.framework를 추가하고, social/social.h 를 임포트한 후에 실행 시킬 수 있습니다.

1. 트윗을 보낼 수 있는지 확인하는 코드
  SLComposerViewController의 isAvailableForServiceType 함수를 통해서 확인할 수 있으며, 전송하지 못할 경우, 사용자에게 적절한 문구를 보여줘야 합니다.

2. 전송한 결과값을 받아야 하는 경우
  completionHandler에 블록 함수를 설정해서, 결과를 받아올 수 있습니다.

3. 초기 메시지 추가
 - setInitialText를 통해서 초기 메시지를 넣을 수 있습니다.

4. 이미지 추가
 - addImage : 이미지를 추가할 수 있습니다.

5. URL 추가
 - addURL: NSURL객체를 추가할 수 있습니다.

source code
#import 
@import Social;
...
- (IBAction)tweetThisPage:(UIBarButtonItem *)sender
{
    if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter]) {
        SLComposeViewController *composer = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];
        [composer setInitialText:@"This is my first tweet in my app!"];
        [composer addImage:[self loadImage]];
        [composer addURL:[NSURL URLWithString:APP_URL_IN_ITUNES]];
        composer.completionHandler = ^(SLComposeViewControllerResult result){
            switch(result) {
                    //  This means the user cancelled without sending the Tweet
                case SLComposeViewControllerResultCancelled:
                    NSLog(@"Canceled");
                    break;
                    //  This means the user hit 'Send'
                case SLComposeViewControllerResultDone:
                    NSLog(@"Tweet Done");
                    break;
            }
        };
        [self presentViewController:composer animated:YES completion:^{
            NSLog(@"Tweet Composer present completed");
        }];
    }else{
        //트위터 아이디가 설정되어 있지 않거나, 인터넷에 연결이 안되어 있는 경우..
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Sorry"
                                                            message:@"You can't send a tweet right now, make sure your device has an internet connection and you have at least one Twitter account setup"
                                                           delegate:self cancelButtonTitle:@"OK"
                                                  otherButtonTitles: nil];
        [alertView show];
    }
}

설정에 트위터 아이디가 설정이 되어 있지 않으면, 아래와 같이 표시가 됩니다.
Twitter ID가 없는 경우
아이디가 설정화면에서 정상적으로 설정이 되어 있으면, 아래와 같이 표시됩니다.
설정된 트위터 아이디로 트윗을 작성중.
만약 작성 중에, 인터넷 연결이 끊기게 되면, 아래와 같이 Post를 하였을 때, 표시됩니다.
개발자가 해준 부분은 없으며, 시스템에서 자동으로 표시하는 화면입니다.
트윗을 보내지 못했을 때, 표시화면
위 화면이 표시될 경우에도, completionHandler에는 정상적으로 전송이 되었다고 결과 값을 리턴하게 되므로, 구분을 잘할 수 있어야 겠습니다.

참고:

 트위터 개발자 센터 문서: Integrating with Twitter on iOS
 Ray Wenderlich : Beginning Twitter in iOS6 Tutorial

2014년 5월 12일 월요일

[iOS] UIScrollView에서 현재 중심이 되는 페이지 얻어오기.

ScrollView에서 페이지 단위로 뷰를 로딩해서 화면에 보여줄 경우, 현재 페이지의 앞뒤 페이지만 로딩하도록 해서 지금 필요한 페이지만 메모리를 사용할 수 있게 만들어야 됩니다.
100페이지의 ScrollView라 할지라도, 현재는 3페이지만 로딩하도록 하는 것입니다.
이 경우, 현재 페이지가 몇 페이지인지 알아야 합니다.

페이지를 가로로 이동하는 경우에는,  페이지의 너비와 현재 페이지의 x좌표를 이용하여 알아낼 수 있습니다.

사용자가 페이지를 터치해서 이동할 경우, scrollView.contentOffset.x 값이 변하게 됩니다.
source code
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    CGFloat pageWidth = self.scrollView.frame.size.width;
    NSInteger page = (NSInteger)floor((self.scrollView.contentOffset.x * 2.0f + pageWidth) / (pageWidth * 2.0f));
    NSLog(@"scrollView.contentOffset.x: %f, page:%d", scrollView.contentOffset.x, page);
    
}

페이지를 왼쪽으로 이동시키다가, 현재 화면의 반을 넘어가는 경우, 다음 페이지가 되고, 오른쪽으로 이동시키다가 현재 페이지의 반 이하가 남게 되면, 이전 페이지로 인식해야 합니다.
현재 페이지 = (x좌표 / 페이지너비 + 0.5)값의 반내림
현재 페이지 = ((x좌표 + 1/2*페이지너비) / 페이지너비) 값의 반내림
현재 페이지 = ((x좌표 + 페이지너비) / (2*페이지너비)) 값의 반내림

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    CGFloat pageWidth = self.scrollView.frame.size.width;
    NSInteger page = (NSInteger)floor((self.scrollView.contentOffset.x * 2.0f + pageWidth) / (pageWidth * 2.0f));
    NSLog(@"scrollView.contentOffset.x: %f, page:%d", scrollView.contentOffset.x, page);
    
}

scrollView가 가로로 Scroll되었을 때, 현재 페이지를 알 수 있으므로, 페이지가 변경되면, 앞뒤 페이지를 로딩하여, 미리 준비하면 됩니다.


[참조] : http://www.raywenderlich.com/10518/how-to-use-uiscrollview-to-scroll-and-zoom-content

[iOS] CALayer를 이용한 액자 모양 그림자 넣기.


기존의 CALayer를 이용해서, shadow를 설정할 수 있었습니다.
그 방식에 shadowPath를 설정하여서 그림자의 모양을 변형하는 방법을 정리합니다.

참조: NSCookbook - iOS Programming Recipe 10: Adding A Shadow To UIView


ViewController에  UIImageView를 하나 추가하고, 아래와 같이 설정을 합니다.
source code
    CALayer *layer = self.imageView.layer;
    layer.shadowOffset = CGSizeMake(1, 1);
    layer.shadowColor = [[UIColor blackColor] CGColor];
    layer.shadowRadius = 3.0f;
    layer.shadowOpacity = 0.80f;

    CGRect rect = self.imageView.frame;
    CGSize size = rect.size;
    CGFloat offset = 15.0f;
    UIBezierPath *path = [UIBezierPath bezierPath]; //Path를 설정
    [path moveToPoint:CGPointMake(0.0, offset)];
    [path addLineToPoint:CGPointMake(size.width, offset)];
    [path addLineToPoint:CGPointMake(size.width, size.height+offset)];
    [path addCurveToPoint:CGPointMake(0.0, size.height+offset)
            controlPoint1:CGPointMake(size.width-offset,size.height)
            controlPoint2:CGPointMake(offset, size.height)];
    [path closePath];
    layer.shadowPath = [path CGPath];

위의 shadowPath를 bezierPath로 만들어서 넣으면 그 Path를 따라서 그림자가 생기게 됩니다.




[참고]
이미지 URL: http://i.dailymail.co.uk/i/pix/2014/05/04/article-2620040-1D92597400000578-908_306x423.jpg

2014년 5월 4일 일요일

[iOS] TextView의 InnerShadow를 만들어 봅니다.

TextView의 배경에 안쪽 그림자를 만들어봅니다.

Inner Shadow가 적용된 화면

위의 그림처럼 TextView에서 InnerShadow를 이미지를 사용하지 않고 넣도록 합니다.

구현 방법은?

일단 배경이미지를 사용해서, 넣을 수도 있는데, 그렇게 되면, 메인 뷰의 배경이 변경이 되면 그것을 따라가지 못하고, 이미지의 색이 배경과 다르게 흰색 태두리가 생길 수 있습니다.
 그래서, CALayer를 이용해서, 그림자 효과로 만들어 봅니다.

- UIView에 대한 그림자 설정.

일단 일반적인 UIView의 CALayer에 그림자 설정과, 태두리를 둥글게 만들어 봅니다.
source code
    UIView *view;
    UIView *view;
    view = self.testView; //코드를 설명을 위해서 대입함.
    view.backgroundColor = [UIColor clearColor]; //배경을 투명하게 설정
    view.layer.cornerRadius = 10.0f;      //테두리 곡선이 되도록 설정 10.0f는 임의의 수
    view.layer.borderColor = [UIColor whiteColor].CGColor; //테두리 색상 흰색
    view.layer.borderWidth = 2.0f;                         //테두리 두께 2포인트
    view.layer.shadowColor = [UIColor blackColor].CGColor; //그림자 검은색
    view.layer.shadowOffset = CGSizeZero;   //그림자 위치는 뷰의 위치와 동일
    view.layer.shadowOpacity = 1.0f;        //그림자 투명도
    view.layer.shadowRadius = 3.0f;         //그림자의 퍼지는 범위 클수록 넓게 그림자 생김.

Storyboard에서 지정한 UITextField에 대해서 위와 같이 설정을 하면, 아래와 같이 표시가 됩니다.
위에서 코드를 추가합니다.
source code
    view.layer.masksToBounds = YES; //바운드 외부로 나가는 것을 Mask처리함
이렇게 하면 외부로 그림자가 나가는 것은 지워집니다.

이제 내부 테두리 비슷한 것이 설정이 되었습니다.
이것을 UITextView에 적용을 하면 아래와 같아집니다.
source code
    self.textView.backgroundColor = [UIColor clearColor];
    view = self.textView; //UITextView로 변경하고 설정함.
    view.backgroundColor = [UIColor clearColor];
    view.layer.cornerRadius = 10.0f;
    view.layer.borderColor = [UIColor whiteColor].CGColor;
    view.layer.shadowColor = [UIColor blackColor].CGColor;
    view.layer.borderWidth = 2.0f;
    view.layer.shadowOffset = CGSizeZero;
    view.layer.shadowOpacity = 1.0f;
    view.layer.shadowRadius = 3.0f;
    view.layer.masksToBounds = YES;

설정은 UIView에 했던것과 동일하고, 이 설정을 TextView에 한 것입니다.
테두리에 그림자가 생기기는 했지만, 내부의 글자에도 그림자가 표시되는 문제가 발생합니다.
이것을 어떻게 처리할 수가 없어서,
TextView의 자리 배경에 UIView를 두어서 TextView의 주변에 inner shadow가 있는 것처럼 설정을 합니다.

source code
-(void)drawInnerShadowOnViewForTextView:(UIView *)view color:(UIColor *)backgroundColor;
{
    UIEdgeInsets insets = {-10, -15, +20, +30};
    CGFloat cornerRadius = 18.5f;
    CGFloat borderWidth = 2.0f;
    CGFloat shadowRadius = 3.5f;
    CGFloat shadowOpacity = 1.0f;
    
    //그림자가 되는 View를 설정합니다.
    UIView *innerShadowView = [[UIView alloc] initWithFrame:CGRectMake(view.frame.origin.x+insets.top, view.frame.origin.y+insets.left, view.frame.size.width + insets.bottom, view.frame.size.height+ insets.right)];
    [innerShadowView setContentMode:UIViewContentModeScaleToFill];
    [innerShadowView setAutoresizingMask : UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
    [innerShadowView.layer setCornerRadius:cornerRadius]; //그림자의 가장자리 곡선
    [innerShadowView.layer setMasksToBounds:YES];
    [innerShadowView.layer setBorderColor: backgroundColor.CGColor]; //외부 배경을 테두리 색으로
    [innerShadowView.layer setShadowColor:[UIColor blackColor].CGColor]; //그림자 색
    [innerShadowView.layer setBorderWidth:borderWidth];
    [innerShadowView.layer setShadowOffset:CGSizeMake(0, 0)];
    [innerShadowView.layer setShadowOpacity:shadowOpacity];
    [innerShadowView.layer setShadowRadius:shadowRadius];
    
    [view.superview insertSubview:innerShadowView belowSubview:view];
}

위와 같이 inner shadow 역할을 하는 UIView를 만들어서, TextView의 바로 아래에 설정을 합니다.
얼추 비슷하게 나왔습니다.
헌데, View의 배경을 변경해 보면, 이상한 현상이 발생합니다.

inner shadow로 추가된 이미지 뒤에 같은 크기의 흰색 배경의 UIView를 추가해 줍니다.
source code
-(void)drawInnerShadowOnViewForTextView:(UIView *)view color:(UIColor *)backgroundColor;
{
    ...위와 동일...
    [innerShadowView.layer setShadowRadius:shadowRadius];

    //추가 시작
    UIView *innerBackgroundView = [[UIView alloc] initWithFrame:innerShadowView.frame];
    [innerBackgroundView setBackgroundColor:[UIColor whiteColor]];
    [innerBackgroundView.layer setCornerRadius:cornerRadius];
    [innerBackgroundView.layer setBorderWidth:borderWidth];
    [innerBackgroundView.layer setBorderColor:backgroundColor.CGColor];
    [innerBackgroundView setAlpha:0.8f];
    
    [view.superview insertSubview:innerBackgroundView belowSubview:view];
    //추가 끝.
    [view.superview insertSubview:innerShadowView belowSubview:view];

}
뷰의 추가 위치가 textView 밑에 innerShadow, 그 밑에 innerBackView가 추가되어야 합니다.
위와 같이 표시가 됩니다.
이제 배경색에 구애 받지 않고, 흰색으로 유지할 수 있습니다.

그리고, 배경화면이 있을 경우에는, TextView와 innerBackView의 alpha를 변경해서, 아래와 같이 표시할 수도 있습니다.


참고되시길 바랍니다.


[참고]
- StackOverflow: UIView create a inner shadow

2014년 5월 1일 목요일

[iOS] Custom TableViewCell의 Button을 통해, 현재 Cell의 indexPath를 알아내는 방법



1. IBAction 함수로 넘기는 sender의 point를 통해서 알아내는 방법

 TableViewController에 IBAction함수를 정의하고, Cell에 있는 Button에서 Touch Up inside 이벤트에 대해서 TabelViewController의 아래 함수로 연결을 합니다.
 그러면, 특정 Cell에서 버튼이 클릭이 되면, 그 버튼객체를 sender로 해서 아래 함수가 호출이 됩니다.
source code
- (IBAction) btnClicked:(id)sender
{
    // (1)
    CGPoint buttonPoint = [sender convertPoint:CGPointZero toView:self.tableView];
    // 2.
    NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:buttonPoint];
    if (indexPath != nil) {
        //Found Cell
    }
}
 (1) Cell 내에 있는 Button을 sender로 받고, 그 sender의 위치 포인트를 알아냅니다.
 - (CGPoint) convertPoint:(CGPoint)point toView:(UIView *)view
: 자신의 좌표 체계에 있는 point 지점을 view의 좌표 체계에서 어느 지점인지 변환함.
즉, Cell 내에 있는 Button의 특정 지점(0,0)을 TableView에서 어느 지점 인지 변환해서 TableView에서의 좌표로 변환을 합니다.
 (2) 그리고, 그 포인트에 해당하는 IndextPath를 찾기 위해서, UITableView의 - indexPathForRowAtPoint를 사용해서, 현재 포인트에 해당하는 indexPath를 구할 수 있습니다.

2. Cell 을 통해서 알아내는 방법

TableView의 함수 중에서 - indexPathForCell:(UITableCell*)를 이용할 수 도 있습니다.
IBAction이벤트를 받은 함수에서 UITableCell을 가져올 수 있다면, 바로 indexPath를 찾을 수 있을 것입니다.
 하지만, 상위 View에서 UITableViewCell을 찾아서 이용해야 합니다.
source code
- (IBAction) btnClicked:(id)sender
{
    NSLog(@"btnClicked : %@", sender);
    UIView *myView = sender;
    UIView *superView = [myView superview];
    while (superView != nil && ![superView isKindOfClass:[DBUTableViewCell class]]) {
        myView = superView;
        superView = [myView superview];
    }
    if (superView != nil) {
        //찾았다.
        NSIndexPath *indexPath = [self.tableView indexPathForCell:(UITableViewCell*)superView];
        if (indexPath != nil) {
            //이제 찾았다.
            [_items removeObjectAtIndex:indexPath.row];
            [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
        }
    }
}

위와 같이 받은 sender를 통해서 상위에 있는 UITableViewCell을 찾고, TableView의 indexPathForCell을 이용해서 알아 낼 수 있습니다.
그러나, iOS6과 iOS7에서 TableViewCell의 구조가 조금 바뀌었기 때문에 달라질 수 있습니다.


참고하시기 바랍니다.

[참조]
http://code.tutsplus.com/tutorials/blocks-and-table-view-cells-on-ios--mobile-22982