앱스토어 제목 문제로 인한 리젝 사유

이번에 업데이트를 하면서 앱 제목에 '무료'라는 키워드를 넣었는데 그 이유로 메타데이터가 거부 당해서 리젝을 당했습니다. 제목에 쓰기에는 부적절한 단어라고 하네요.. 그래서 예전에 무료라는 키워드를 어플 제목에 쓰는 것들을 찾아봤더니 대부분 3년전 업데이트가 마지막인 어플들이 많았습니다. 1~2년 전부터 새로 생긴 가이드 인거 같습니다.


리젝 사유

Guideline 2.3.7 - Performance - Accurate Metadata

Your app name or subtitle to be displayed on the App Store includes keywords or descriptors, which are not appropriate for use in these metadata items.

Specifically, the following words in your app name or subtitle are considered keywords or descriptors:

  • 무료

Next Steps

To resolve this issue, please revise your app name or subtitle to remove any keywords and descriptors from all localizations of your app. Keywords can be entered in the Keywords field in App Store Connect to be used as search terms for your app.

Before submitting your app to the App Store, ensure there are no unnecessary phrases, words, or descriptions in the app's name, description, icons, preview, or other metadata fields. As a best practice, your app's metadata should communicate the app's value in as few words as possible.


해결 방안

앱 제목에 '무료'라는 키워드를 삭세하고 다시 리뷰를 받아서 무사히 통과 되었습니다.

마치며

앱 제목에 '무료'라는 키워드가 있는 이유로 리젝을 당한거였는데 시간이 지나면 지날수록 바뀌는 애플 가이드라인 때문에 따로 공부를 해야되는게 아닌가 싶습니다. 리뷰 시간이 예전에 비하면 많이 줄긴 했지만 업데이트, 출시 시간이 촉박 할 수록 정말 피말리게 하는거 같습니다. 틀린점이나 궁금한 점 있으면 언제든지 댓글을 남겨 주세요 :)



UIColor 비교하기


설명

두개의 UIColor 똑같은지 아닌지 비교 하는 코드 입니다. UITextView는 Placeholder(힌트 텍스트)를 UITextFeild처럼 따로 지원 해주지 않기 때문에 텍스트 색을 비교해서 현재 텍스트가 힌트라는걸 판별 할때 저는 사용합니다.


사용환경

* Swift 4.2
* XCode 10.0

코드

//Objective-C
- (BOOL)color:(UIColor *)color1 isEqualToColor:(UIColor *)color2 withTolerance:(CGFloat)tolerance {
    CGFloat r1, g1, b1, a1, r2, g2, b2, a2;
    [color1 getRed:&r1 green:&g1 blue:&b1 alpha:&a1];
    [color2 getRed:&r2 green:&g2 blue:&b2 alpha:&a2];

    return
    fabs(r1 - r2) <= tolerance &&
    fabs(g1 - g2) <= tolerance &&
    fabs(b1 - b2) <= tolerance &&
    fabs(a1 - a2) <= tolerance;

}

//Swift
func isColor(_ color:UIColor, color2:UIColor, tolerance:CGFloat) -> Bool {
        var r1 : CGFloat = 0, g1 : CGFloat = 0, b1 : CGFloat = 0, a1 : CGFloat = 0
        var r2 : CGFloat = 0, g2 : CGFloat = 0, b2 : CGFloat = 0, a2 : CGFloat = 0

        color.getRed(&r1, green:&g1, blue:&b1, alpha:&a1)
        color2.getRed(&r2, green:&g2, blue:&b2, alpha:&a2)

        return abs(r1-r2) <= tolerance && abs(g1-g2) <= tolerance && abs(b1-b2) <= tolerance && abs(a1-a2) <= tolerance
    }

맞치며

막상 포스팅을 하고나니깐 생각보다 활용을 할만한 곳이 생각이 안 나는거 같습니다,, 궁금하신점이나 틀린점이 있으면 댓글로 남겨주세요 감사합니다 :)





앱스토어에서 어플 정보 받아오기


설명

이번 포스팅은 앱스토어에 올라가있는 어플에 대해서 정보를 가져오는 방법입니다. 생각보다 많이 사용이 될까 생각이 들지만 단순 버전관리라던지 여러가지로 사용 할수 있습니다. (저는 버전관리때문에 사용해 봤습니다.)
http://itunes.apple.com/lookup?bundleId=번들 아이디
이 조합으로 쉽게 텍스트 파일을 받아온 후 JSON 형식으로 받아서 사용하면 됩니다.


사용환경

* Swift 4.2
* XCode 10.0

코드

//Objective-C
NSDictionary* infoDictionary = [[NSBundle mainBundle] infoDictionary];
NSString* appID = infoDictionary[@"CFBundleIdentifier"];
NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"http://itunes.apple.com/lookup?bundleId=%@", appID]];
NSData* data = [NSData dataWithContentsOfURL:url];
NSDictionary* lookup = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];

if ([lookup[@"resultCount"] integerValue] == 1){
    NSString* appStoreVersion = lookup[@"results"][0][@"version"];
     NSString* currentVersion = infoDictionary[@"CFBundleShortVersionString"];

    NSLog(@"Need to update [%@ != %@]", appStoreVersion, currentVersion);
}

//Swift
guard let infoDic = Bundle.main.infoDictionary,
            let appID = infoDic["CFBundleIdentifier"] as? String,
            let url = URL(string: "http://itunes.apple.com/lookup?bundleId=\(appID)") else {
            print("gaurd error")
            return
        }

        do {
            let data = try Data(contentsOf: url)
            let json = try JSONSerialization.jsonObject(with: data, options: [])
            guard let dic = json as? NSDictionary else {
                print("guard error")
                return
            }
            if dic.object(forKey: "resultCount") as? Int != 0 {
                //Do Something
                print(dic)
            } else {
                print("not result")
            }
        } catch {
            print(error.localizedDescription)
        }

맞치며

해당 아이디의 앱스토어에 올라가있는 정보입니다. 생각보다 많은 정보를 내려줍니다. 앱스토어 홈페이지가 아니 다른 사이트에서 보여줄때 이런식으로 정보를 받아와서 보여주는거 같습니다. 여담이지만 JSON은 아직까지 라이브러리 통해서 쓰는게 나은거 같습니다.. 틀린점이나 궁금한점 있으면 댓글 남겨주세요. 감사합니다 :)





문자열의 처음, 마지막 지정된 개수만큼 지우기


설명

이번 포스팅은 문자열의 앞뒤 문자를 지우는 메소드 입니다.
문자열의 길이 만큼만 자를수 있기때문에 고정된 길이의 문자열에서만 사용해야됩니다. 안 그럴경우 Range over로 인해 앱이 튕기게 됩니다. 간단하게 dropLast(:), dropFirst(:)의 메소를 이용해서 자를수 있습니다.


사용환경

* Swift 4.2
* XCode 10.0

코드

let str = "You Know Programing?"
print("original = \(str)") //output = original = You Know Programing?
let drop_last = String(str.dropLast(3))
print("Last Drop index 3 = \(drop_last)") //output = Last Drop index 3 = You Know Programi
let drop_first = String(str.dropFirst(3))
print("First Drop index 3 = \(drop_first)") // output = First Drop index 3 =  Know Programing?

맞치며

문자열 길이에 따라 앱이 죽을수도있기 때문에 자르려고 하는 길이가 문자열 길이보다 적은지 항상 확인 해주고 사용해야됩니다.
궁금한점이나 틀린점이 있다면 댓글 남겨주세요. 감사합니다 :)





네비게이션바 뒤로가기 제스쳐


설명

네비게이션바에 있는 기본적인 제스쳐 입니다. 화면 왼쪽끝에서 오른쪽으로 밀어서 전 화면으로 돌아가는 제스쳐입니다.
아이폰 유저에게는 정말 익숙한 화면전환 제스쳐 입니다. 제스쳐 활성화를 하지 않으면 전혀 반응을 하지 않습니다. 맨 상위뷰에서 해주시면 하위뷰에는 자동으로 적용됩니다.


사용환경

* Swift 4.2
* XCode 10.0

코드

class Main: UIViewcontroller, UIGestureRecognizerDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()

        self.navigationController?.interactivePopGestureRecognizer?.delegate = self
    }
}

맞치며

코드 한줄로 간단하게 구현이 가능합니다.(처음 아이폰 개발 시작할때.. 몰라서 정말 많이 삽질 했었습니다..)
틀린점이나 궁금한점 있으시면 댓글 남겨주세요. 감사합니다 :)





최상단 뷰컨트롤러 가져오기


설명

뷰가 많이 중첩 되다보면 잘못된 구조로 인해 뷰 전환등을 사용을 못하게 되는 경우가 있습니다. 그렇게 안 만드는 것이 제일 중요하지만 디자인등 여러가지를 고려하다보면 피치 못하게 만들어지는 경우가 많습니다. 그럴때 사용 하면 유용한 extension 입니다.


사용환경

* Swift 4.2
* XCode 10.0

코드

extension UIApplication {
    class func topViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
        if let nav = base as? UINavigationController {
            return topViewController(base: nav.visibleViewController)
        }
        if let tab = base as? UITabBarController {
            if let selected = tab.selectedViewController {
                return topViewController(base: selected)
            }
        }
        if let presented = base?.presentedViewController {
            return topViewController(base: presented)
        }
        return base
}

//사용 방법
if let topVC = UIApplication.topViewController() {
     topVC.present(UIViewController(), animated: true, completion: nil)
}

맞치며

정말 뷰 계층에 공부가 필요한 이유중 하나입니다. 뷰계층 구조를 무시하고 만들다보면 진짜 어마어마한 결과물이 나옵니다,, 물론 개발자가 잘못 만드는 경우도 있지만 디자인 때문에 어쩔 수 없게 나오는 경우도 많습니다. 디자이너, 기획자와 잘 얘기(?)를 해서 원만하게 해결하는 것도 좋은 방법중 하나입니다. 틀린점이나 궁금한점은 댓글 남겨 주시면 답변 해드리겠습니다. 감사합니다 :)





UIScrollView 상단, 하단 이동시키기


설명

이번 포스트에서는 UIScrollView 상,하단으로 이동하는 코드 입니다. UITableView, UICrollectionView등 UIScrollView를 상속받은 모든 뷰에서 사용이 가능합니다. ScrollRectToVisible or setContentOffset 메소드를 통해 어디든지 원하는 위치에 스크롤로 이동 시킬 수 있습니다.


사용환경

* Swift 4.2
* XCode 10.0

코드

테이블뷰(스크롤뷰) 상단으로 이동하는 코드

yourScrollView.scrollRectToVisible(CGRect(x: 0, y: 0, width: 1, height: 1), animated: true)

or

yourScrollView.setContentOffset(CGPoint(x: 0, y: 0), animated: true)

테이블뷰(스크롤뷰) 하단으로 이동하는 코드

yourScrollView.scrollRectToVisible(CGRectMake(0,
                                               yourScrollView.contentSize.height-yourScrollView.bounds.height,
                                              yourScrollView.bounds.size.width,
                                              yourScrollView.bounds.size.height),
                                   animated: true)

or

yourScrollView.setContentOffset(CGPoint(x: 0,
                                        y: yourScrollView.contentSize.height-yourScrollView.bounds.height),
                                animated: true)

맞치며

UIScrollView를 사용해서 작업을 할 경우 유용하게 사용되는 메소드 입니다. 틀린점이나 궁금한점 있으면 댓글을 남겨주세요. 감사합니다 :)



원하는 방향만 둥글게 하기


설명

뷰를 만들다 보면 전체를 둥글게 하는것이 아니라 특정 방향만 둥글게 해줘야 되는 경우가 있습니다. UIView 상속 받은 모든 컴포넌트에 해당되는 내용입니다.


사용환경

* Swift 4.2
* XCode 10.0


코드

// Swift // 오른쪽위와 오른쪽아래를 둥글게 let contentImage = UIView()
contentImage.frame = CGRectMake(64, 64, 55, 55)
contentImage.backgroundColor = UIColor.redColor()
let maskPath = UIBezierPath(roundedRect: contentImage.bounds, byRoundingCorners: [UIRectCorner.TopRight, UIRectCorner.BottomRight], cornerRadii: CGSizeMake(3.0, 3.0))
let maskLayer = CAShapeLayer()
maskLayer.frame = contentImage.bounds
maskLayer.path = maskPath.CGPath
contentImage.layer.mask = maskLayer
view.addSubview(contentImage)


// Objective-C
// 오른쪽위와 오른쪽아래를 둥글게
UIView * ContentImage = [[UIImageView alloc]initWithFrame:CGRectMake(64, 64, 55, 55)];
ContentImage.backgroundColor = [UIColor redColor];
UIBezierPath * maskPath;
maskPath = [UIBezierPath bezierPathWithRoundedRect:ContentImage.bounds byRoundingCorners:(UIRectCornerTopRight | UIRectCornerBottomRight) cornerRadii:CGSizeMake(3.0, 3.0)];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = ContentImage.bounds;maskLayer.path = maskPath.CGPath;
ContentImage.layer.mask = maskLayer;
[self.view addSubview:ContentImage];

둥글게 하고 싶은 모서리의 방향을 UIRectCorner 속성을 추가 해주시면 됩니다. UIRectCorne 종류는 밑에 표를 참조 하시면 됩니다.

Objective-C Swift
전체 UIRectCornerAllCorners UIRectCorner.allCorners
왼쪽 위 UIRectCornerTopLeft UIRectCorner.topLeft
왼쪽 아래 UIRectCornerBottomLeft UIRectCorner.bottomLeft
오른쪽 위 UIRectCornerTopRight UIRectCorner.topRight
오른쪽 아래 UIRectCornerBottomRight UIRectCorner.bottomRight

맞치며

작업을 하다보면 이미지 보다 UIView 또는 다른 컴포넌트 뷰를 이용해서 만드는 경우가 더 편하고 손쉽게 만들어지는 경우도 있습니다. 물론 단순 이미지보다는 손은 더 갑니다. 디자인을 보다보면 이쁜 디자인을 위해 둥근 모서리를 이용하는 경우가 많습니다. 위에 코드를 위해 원하는 모양을 손쉽게 만들수있습니다. 틀린점이나 궁금한점 있으시면 댓글을 남겨주세요. 감사합니다.



클립보드로 텍스트 복사

설명

가끔 앱을 만들다 보면 클립보드에 텍스트를 복사하는 경우가 필요합니다.
코드 한줄이면 원하는 텍스트가 클립보드에 복사가 되며, 다른 텍스트 적는 곳에 가서 붙여 넣기를 할 수 있습니다.


사용환경

* Swift 4.2
* XCode 10.0


코드

//Swift
UIPasteboard.general.string = "ex)안녕하세요"

//Objective-C
[[UIPasteboard generalPasteboard] setString:@"안녕하세요"];


맞치며

사용자들에게 텍스트 관련 편의성을 제공하는 메소드 입니다. 초대코드나 내 앱이 아닌 다른 앱에서 텍스트를 사용해야할 경우 유용하게 쓰입니다.
틀린점이나 수정해야 할 부분이 있으면 댓글 남겨주세요! 감사합니다 :)



Int형 천단위 콤마 찍고 스트링으로 변환해주기

설명

보통 돈을 나타낼때 천자리마다 콤마(,)를 찍습니다. Int형 값에 천단위마다 콤마(,)를 찍어주고 String형 값으로 변환해주는 소스 입니다.


사용환경

* Swift 4.2
* XCode 10.0


코드

//Swift 코드
let intValue: Int = 1000

let value: NSNumber = intValue as NSNumber
print("NSNumber = \(value)")
let formatter = NumberFormatter()
formatter.numberStyle = .decimal

guard let resultValue = formatter.string(from: value) else { return }
print("Result Value = \(resultValue)")


//출력 결과
NSNumber = 1000
Result Value = 1,000


//Objective-C
NSNumberFormatter * numFormatter = [[NSNumberFormatter alloc] init];
[numFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
int value = 1000;
NSString * price = [NSString stringWithFormat:@"%@", [numFormatter stringFromNumber:[NSNumber numberWithInt:value]]];


맞치며

단위가 관련된 앱을 만들다 보면 많이 사용되는 방법 중 하나입니다. 틀린점이나 궁금한점 있으면 댓글 남겨주세요 :)


+ Recent posts