2016년 2월 25일 목요일

테이블 뷰셀에 버튼 이벤트 처리 하기

테이블 뷰셀에 on/off 를 표시하는 버튼이 있다고 할때

동적 테이블뷰에 수많은 테이블 뷰 셀에 on/off를 처리 할려면 어떻게 해야 하나?

tableViewCell 클래스 코드에 evnent를 작성한다.??

물론 보여주기만 한다면 가능 하다.

outlet을 tableView.xib에서 tableViewCell 클래스로 버튼을 연결해서 이벤트코드를 작성 하면
보여주는 기능 만 처리 할때는 충분 하다.


하지만 이를 이용하는  TableViewController 에서 어떤 talbeViewCell이 on인지 off인지
어떻게 알아 차릴수가 있을까?

이렇게 접근하면 곤란 하다.

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
       cell.onoffButton.tag = indexPath.row
        cell.onoffButton.addTarget(self, action: "onoffButtonConnected:", forControlEvents: .TouchUpInside)
        
        return cell
}

위와 같이 onoffButton  (테이블뷰셀에 버튼) 에 tag 값을 해당 row의 indexPath.row로 설정 하고
이벤트 함수를  addTarget을 이용해서 걸어 준다.

    func onoffButtonConnected(sender : UIButton!) {
        sender.selected = !sender.selected
        
        if self.morningcalldata[sender.tag]["setting"] == "ON" {
           self.morningcalldata[sender.tag]["setting"] = "OFF"
        } else {
           self.morningcalldata[sender.tag]["setting"] = "ON"
        }
    }


이벤트 함수에서는 tag 값을 다시 index로 이용하여 데이터 처리까지 할 수 있다.

아카이브 파일을 이용한 swift key value 저장

알람 리스트를 저장한다고 해보자

오전 , 오후, 시간, 반복, 설정  이러한 key와 이에 대한 value

다음과 같은 key value 쌍으로 정의 하면

 ["ampm":"오전","time":"06:00","repeat":"월화수목금","setting":"OFF"],

이러한 데이터를 저장하는 swift의 데이터 형은 어떻게 선언 하는가

[String : String]

이러한 데이터를 array로 처리 하니 다음과 같은 타입이 된다.
 [[String: String]] 

이러한 데이터를 파일로 저장했다가 필요에 따라 로드 하고 변경이되면 저장 해야 한다.

NSKeyedUnarchiver, NSKeyedArchiver를 이용하여 저장 하고 불러 올수 있다.

사용자 경로 처리를 위한 helper 클래스
class Helper {
    
    static let sharedInstance = Helper()
    
    static func getDocumentsDirectory() -> NSString {
        let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
        let documentsDirectory = paths[0]
        return documentsDirectory
    }
}




사용자 경로에서 moriningcall.archive로 저장을 하고 불러오는 코드는 대략 아래와 같다.

다음과 같이 어레이를 선언 한다.
var morningcalldata: [[Sting:String]]!


let filemgr = NSFileManager.defaultManager()
        
        let filename = Helper.getDocumentsDirectory().stringByAppendingPathComponent("morningcall.archive")
        if filemgr.fileExistsAtPath(filename) {
            morningcalldata = NSKeyedUnarchiver.unarchiveObjectWithFile(filename) as! [[String: String]]
        } else {
            //디폴트 데이터
            morningcalldata = [
                        ["ampm":"오전","time":"06:00","repeat":"월화수목금","setting":"OFF"],
                        ["ampm":"오전","time":"06:00","repeat":"월화수목금","setting":"OFF"],
                        ["ampm":"오전","time":"06:00","repeat":"월화수목금","setting":"OFF"],
                        ["ampm":"오전","time":"06:00","repeat":"월화수목금","setting":"OFF"],
                        ["ampm":"오전","time":"06:00","repeat":"월화수목금","setting":"OFF"]
                    ]
            //최초 save
            NSKeyedArchiver.archiveRootObject(morningcalldata, toFile: filename )
        }

2016년 2월 21일 일요일

swift로 특정일이 현재로 부터 몇일전 "5 days ago" 이런 문자열을 만들때.

몇일전
몇시간전
몇분전

등등...

이런 정보를 표시해야 하는 경우가 있다.

NSDate의 extension으로 다음과 같이 구현 한다음

이를 이용하면 가능 하다.

import Foundation

extension NSDate {
    func yearsFrom(date:NSDate) -> Int{
        return NSCalendar.currentCalendar().components(.Year, fromDate: date, toDate: self, options: []).year
    }
    func monthsFrom(date:NSDate) -> Int{
        return NSCalendar.currentCalendar().components(.Month, fromDate: date, toDate: self, options: []).month
    }
    func weeksFrom(date:NSDate) -> Int{
        return NSCalendar.currentCalendar().components(.WeekOfYear, fromDate: date, toDate: self, options: []).weekOfYear
    }
    func daysFrom(date:NSDate) -> Int{
        return NSCalendar.currentCalendar().components(.Day, fromDate: date, toDate: self, options: []).day
    }
    func hoursFrom(date:NSDate) -> Int{
        return NSCalendar.currentCalendar().components(.Hour, fromDate: date, toDate: self, options: []).hour
    }
    func minutesFrom(date:NSDate) -> Int{
        return NSCalendar.currentCalendar().components(.Minute, fromDate: date, toDate: self, options: []).minute
    }
    func secondsFrom(date:NSDate) -> Int{
        return NSCalendar.currentCalendar().components(.Second, fromDate: date, toDate: self, options: []).second
    }
    func offsetFrom(date:NSDate) -> String {
        if yearsFrom(date)   > 0 { return "\(yearsFrom(date))y"   }
        if monthsFrom(date)  > 0 { return "\(monthsFrom(date))M"  }
        if weeksFrom(date)   > 0 { return "\(weeksFrom(date))w"   }
        if daysFrom(date)    > 0 { return "\(daysFrom(date))d"    }
        if hoursFrom(date)   > 0 { return "\(hoursFrom(date))h"   }
        if minutesFrom(date) > 0 { return "\(minutesFrom(date))m" }
        if secondsFrom(date) > 0 { return "\(secondsFrom(date))s" }
        return ""
    }

}

사용하는 방법은 다음과 같다.

lastSportData.year, mont, day 값을 NSDate로 만들어서 현재 NSDate와의 몇일 차이인지 문자열을 만든다.

            let date = NSDate()
            let day = date.daysFrom(makedate(lastSportData.year, month: lastSportData.month, day: lastSportData.day))
            if day > 0 {
                agoLabel.text = "\(day)days ago"
            } else {
                agoLabel.text = "today"
            }




2016년 2월 15일 월요일

swift Array Filter 사용하기

swift 에서 key valeu를 저장 하는 Array를 TableView로 적잘한  cell에 UI 컴퍼넌트들과 연결 하여 데이터를 보여 주고 있다고 할 때

여러 리스트 중에 특정한 값 만을 표시 하는 경우가 있다.

예를 들어 결재 내역에서 point 라는 항목을 전체 표시
차감만 표시
적립만 표시

해야 하는 경우는

ex)

    var mileageData = [
        ["point":"save", "price":"7000", "datetime":"2016.01.08 16:50", "message":"관리자가 마일리지 부여"],
        ["point":"used", "price":"10000", "datetime":"2016.01.08 16:50", "message":"관리자가 마일리지 부여"],

    ]


여기서 point key의 save만 , used만을 필터 처리 하고 싶은 경우가 있다.


filter() 메소드를 이용하면 된다.


        if filterButtons[0].selected == true { //전체
            mileageData = mileageDataOrigin
            
        } else if filterButtons[1].selected == true { //적립
            mileageData = mileageDataOrigin.filter({
                $0["point"] == "save"
            })
        } else { //차감
            mileageData = mileageDataOrigin.filter({
                $0["point"] == "used"
            })
        }
        tableView.reloadData()

위 코드는 mileageDataOrigin 으로 부터 mileageData Array를 point 키의 값을 기준으로 
필터 처리를 하여 재구성 하는 코드이다.

tableView.relaodData()를 이용하여 테이블뷰의 데이터를 새로 갱신 하면 변경된 데이터가 표시 된다.

2016년 1월 29일 금요일

커스텀 스위치 버튼 만들기





UISwitch 가 있지만



커스텀한 스위치 버튼을 디자인 가이드에 있다면

백그라운드 이미지를 적용하고
버튼 이미지를 적용

select 되었을 때 버튼 이미지를 우측으로
unselect 되었을 때 버튼 이미지를 다시 좌측으로 이동 해야 한다.

어떻게 하나?


프로퍼티에서 inset을 변경 시켜야 한다.

default / selected에서 이값을 설정 해놓을 수는 없다.

나머지는 코드로 해결 해야 한다.

우측으로

            self.backgroundSyncButton.imageEdgeInsets = UIEdgeInsetsMake(0, 25, 0, 5)

좌측으로
            self.backgroundSyncButton.imageEdgeInsets = UIEdgeInsetsMake(0, 5, 0, 5)

그럼 스위치 버튼 만들기 끝


2016년 1월 28일 목요일

UIProgressView 트랙, 프로그래스 커스텀 이미지 적용 버그 해결 방법










지난번에
http://mtsparrow.blogspot.kr/2016/01/uiprogress-view-height.html


UIProgressView 컨트롤에 Height 문제도 있었지만

그 외에 도 문제가 있다.

커스텀한  프로그래스 이미지와 트랙이미지를 아무리  인터페이스 빌더에서
적용해 주어도 효과가 없다.

이에 대한 해결 방밥은

https://gist.github.com/JohnEstropia/9482567

여기에서 찾을수 있다.

JEProgressView라는 클래스 이름으로 UIProgressView를 상속 받아 문제를
해결 하였다.

이를 이용하여 Track 이미지 Progress 이미지를 설정 하면 제대로 된 결과를 얻을 수 있다.


2016년 1월 23일 토요일

네비게이션 바에 컬러 아이콘으로 버튼을 만들고 거기에 넘버링 까지 하려면



이러한 화면을 구성 하려면 어찌 합니까? 어떻게 할까요?

우선 네비게이션바에 바버튼 이미지는 단색으로 설정된다.

        let btImage = Helper.textToImage("1", inImage: UIImage(named: "bt_topmenu_bell_on")!, atPoint: CGPoint(x: 26, y: 21))
        
        

        let rightButton2: UIBarButtonItem = UIBarButtonItem(image: btImage.imageWithRenderingMode(.AlwaysOriginal), style: UIBarButtonItemStyle.Plain, target: self, action: "")


위 코드에서  btImage.imageWithRenderingMode(.AlwaysOriginal) 
이를 설정 해 줘야 네비게이션바에 바버튼 이미지를 원래 색상으로 처리 한다.

btImage 즉 벨 아이콘에 숫자 넘버링을 위한 코드는 helper 클래스를 만들어서 이용 하였다.

아무데서나 편하게 쓰기 위한 helper 클래스를 만들고 거기에 
text와 이미지, 그리고 포지션을 주면 이미지위에  text를 표시하는 함수를 작성 해서 이용한다.

// 이미지 위에 글 쓰기 (넘버링)
    static func textToImage(drawText: NSString, inImage: UIImage, atPoint:CGPoint)->UIImage{
        
        // Setup the font specific variables
        let textColor: UIColor = UIColor.whiteColor()
        let textFont: UIFont = UIFont(name: "Helvetica Bold", size: 9)!
        
        //Setup the image context using the passed image.
        UIGraphicsBeginImageContext(inImage.size)
        
        //Setups up the font attributes that will be later used to dictate how the text should be drawn
        let textFontAttributes = [
            NSFontAttributeName: textFont,
            NSForegroundColorAttributeName: textColor,
        ]
        
        //Put the image into a rectangle as large as the original image.
        inImage.drawInRect(CGRectMake(0, 0, inImage.size.width, inImage.size.height))
        
        // Creating a point within the space that is as bit as the image.
        let rect: CGRect = CGRectMake(atPoint.x, atPoint.y, inImage.size.width, inImage.size.height)
        
        //Now Draw the text into an image.
        drawText.drawInRect(rect, withAttributes: textFontAttributes)
        
        // Create a new image out of the images we have created
        let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
        
        // End the context now that we have the image we need
        UIGraphicsEndImageContext()
        
        //And pass it back up to the caller.
        return newImage
    }