2016년 5월 18일 수요일

Swift - optional 에서 ! 와 ? 사용법

이후 사용할 때 확정형 선언은 "!"
아직 nil 이 아니라는 확신이 없으면 "?"

var resultInt:Int

var optionalWithSuspicious:Int?
optionalWithSuspicious = 3
print(optionalWithSuspicious)     ‘Optional(3)’
resultInt = optionalWithSuspicious!+3

var optionalWithSure:Int!
optionalWithSure = 3
print(optionalWithSure)               ‘3’

resultInt = optionalWithSure+3


Swift - main story board 활용한 화면 전환 tip

xcode 에는 UI 디자인을 위한 main story board 라는 툴을 제공한다.

화면 전환은 2가지 방법이 존재한다.

1. Modal Popup
2. Push


modal popup 세그메뉴 present modally
push 세그메뉴 show (navigation controller 필히 있어야 함)


참조 github

https://github.com/GlennHKim/iphone_view_transition


2016년 5월 17일 화요일

Swift - struct 와 class 로 배워 보는 Call by Value / Call by Reference


// 스트럭트
struct Task {
    var title:String
    var time:Int?
}

var callTask = Task(title: "Call to randy", time: 10*60)
var reportTask = Task(title: "Report to boss", time: nil)

var todayTask : [Task] = []
todayTask += [callTask, reportTask]

todayTask[1].time = 15*60
callTask.title = "Call to toby"

print("today task = \(todayTask) \r\n callTask = \(callTask)")


// 클래스
class TaskClass {
    var title:String
    var time:Int
    
    init(title:String, time:Int){
        self.title = title
        self.time = time
    }
}

var callTask2 = TaskClass(title: "Call to randy", time: 10*60)
var reportTask2 = TaskClass(title: "Report to boss", time: 10*80)

var todayTask2 : [TaskClass] = []
todayTask2 += [callTask2, reportTask2]

todayTask2[1].time = 15*60
callTask2.title = "Call to toby"


print("today task = \(todayTask2[0].title) \r\n callTask = \(callTask2.title)")




실행 결과는

today task = [Task(title: "Call to randy", time: Optional(600)), Task(title: "Report to boss", time: Optional(900))] 
 callTask = Task(title: "Call to toby", time: Optional(600))
today task = Call to toby 
 callTask = Call to toby

Swift - Protocol 기본

protocol EngineProtocol {
    var name:String { get set }   // name 이라는 이름을 갖고 get/set 가능 property
    func startEngine()
    func stopEngine()
}

//class NewEngine: Engine, EngineProtocol {   // Objective-c 다르게 상속과 protocol 준수를 선언하는 부분이 동일
class NewEngine: EngineProtocol {
    var name:String
    
    init(){
        name = "New Engine"
    }
    
    func startEngine() {
        print("New Start Engine!")
    }
    
    func stopEngine() {
        print("New Stop Engine")
    }
    

}

Swift - Class 기본

import Foundation

class Engine{
    var name:String
    
    // 클래스 초기화 함수
    init(initName:String){
        self.name = initName
    }
    
    init(){
        self.name = "Normal Engine"
    }
    
    func startEngine(){
        print ("Start Engine!")
    }
    
    func stopEngine(){
        print("Stop Engine")
    }
}

var myEngine = Engine(initName:"8기통")

class Tire{
    let name:String
    
    init(initName:String){
        name = initName
    }
}

var myTire = Tire(initName: "신발보다 타이어")

class Car{
    var engine:Engine
    var tire:Tire
    
    init(){
        engine = Engine(initName: "8기통 엔진!")
        tire = Tire(initName: "금호 타이어")
    }
    
    func Start() -> Bool{
        engine.startEngine()
        return true
    }
}

let car = Car()
car.engine.name
car.tire.name
let result = car.Start()

print(myEngine.name + " " + myTire.name)

class SuperEngine: Engine{
    var year:String     // 저장 Property
    
    var info:String{    // 연산 Property
        get {
            return name + year
        }
        set {
            let index = newValue.endIndex.advancedBy(-4)    // newValue setter 인자로 들어오는 값을 담는 변수
            year = newValue.substringFromIndex(index)
            name = newValue.substringToIndex(index)
        }
    }
    
    override init() {
        year = "0000"
        super.init()
        name = "Super Engine"
//        super.name = "Super Engine"
//        self.name = "Super Engine"
    }
    
    func speedUp(){
        print("Speed Up!")
    }
}

car.engine = SuperEngine()
car.engine.name

// 타입 캐스팅
var superEngine = car.engine as! SuperEngine
superEngine.speedUp()
superEngine.info
superEngine.info = "Hyper Engine2016"
superEngine.info
superEngine.name

superEngine.year

Swift - for 사용

let theRatings = [1,2,3,4,5]

// 가장 기본 적인 for
for rate in theRatings{
    print(" 점수는요~ \(rate)")
}

// ... 연산자를 이용한 for
for i in 0...7 {
    print("\(i+1)번째 반복 ")
}

// ..< 연산자를 이용한 for
for i in 0..<7 {
    print("7 반복")
}

// 굳이 증분 값을 참조하지 않는 경우 '_' 이용
for _ in 0...7 {
    print("8 반복")

}

Swift - func 함수 선언 지시자


func getValue() -> Double {
    return 3.31
}

getValue()


func getTuple(strName:String, withAge:Int) -> (name:String, age:Int){
    return (strName, withAge)
}

getTuple("Jsson lee", withAge: 39).name


func myNewFunc(tuple:(name:String, age:Int)) -> String {
    return tuple.name
}

myNewFunc(("nicegood", 13))

func funcWithoutReturn() {
    print("this is non-returnable function")
}

funcWithoutReturn()

func funcWithDefaultParameter(inputName:String="JOHN DOE", age:Int) -> (killCount:Int, lastAccessPoint:String) {
    return (age, "Kill House")
}


funcWithDefaultParameter("hello", age: 3)

var newDate = NSDate()

func getAveList(scores:Int..., total:Double) -> Double {
    var total = 0
    for p in scores{
        total += p
    }
    return Double(total)/Double(scores.count)
}

func getAve(scores:[Int]) -> Double {
    var total = 0
    for p in scores{
        total += p
    }
    return Double(total)/Double(scores.count)
}

getAve([0,0,0,1,2,3,4])
getAveList(1,2,3,4, total:3.1)


var value = 12

func testFun(var param:Int) -> Int {
    param += 1
    return param
}

print(testFun(value))
print(value)

var value2 = 12

func testFun2(inout param:Int) -> Int {  // inout 지시자는 원형타입의 파라미터 주소값을 넘기는 형태로 함수 실행토록 해줌
    param += 1
    return param
}

print(testFun2(&value2))

print(value2)

Swift - Optional 개론

1. Optional 이란?
 '값이 없을 수 있는 가능성' 을 다루는 개념
 c/c++ 혹은 java 등에서 메모리주소 혹은 객체의 포인터를 다루는 언어에서 null / nil 을 다루는 데 문제가 많음.

2. Optional 선언

var ratings:[Int]? = nil

var optInt:Int?
var optStr:String?

var optArr:[String]?

 선언할 때 '?'를 써 넣어 주면 Optional로 되고 이 변수에다가는 nil을 할당할 수 있다.
 혹은 선언만 하면 해당 변수는 nil로 세팅 된다.

3. Optional의 사용법

// 안되는 예
// 옵셔널 값을 반환 . Int("ABC") 경우 오류가 발생할 대비하기 위해
var getInt = Int("123")

var b = 10 + getInt // 컴파일 오류, getInt Optional 래핑되었기 때문에

// 되는 예1 - 강제 언래핑
var b = 10 + getInt! // 실제 언래핑 시점에 값이 여전히 nil인 경우 런타임에러

// 되는 예2 - 좀 더 부드러운 사용
ratings = [1,2,3,4]

if let theRatings = ratings {
    for rate in theRatings{
        print(" 점수는요~ \(rate)")
    }

}





2016년 5월 13일 금요일

Objective-C autorelease 지시자와 @autoreleasepool 지시자 - ARC가 활성화되지 않은 경우 이용

// Manager.m

@implementation Manager
-(void) startDraw{
    Rectangle *rect = [[Rectangle alloc]init];
    [rect setDelegate:self]; // RectangleProtocol 따라야 .
    [rect draw];
}
-(void) testMethod{
    NSLog(@"Test Method.");
}
-(Shape*) getNewShape{
    Shape *newShape = [[Shape alloc]init];
    return newShape;
}

@end

// main.m

#import <Foundation/Foundation.h>
#import "Manager.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Manager *manager = [[Manager alloc]init];
        [manager startDraw];
        
        Shape* newShape = [manager getNewShape];
    }
    return 0;
}

메모리 관리를 수동으로 하면서 위의 코드 처럼 Shape* 객체를 하나 함수 호출로 받아왔다.
이 객체의 메모리 해제 시점(release)은 언제로 하는게 좋을까??

1. 일반적인 메모리 해제 수순
return 하기 전에 해제해 버린다??

-(Shape*) getNewShape{
    Shape *newShape = [[Shape alloc]init];
    [newShape release]
    return newShape;
}

그럼 이 함수를 호출하는 입장에서는 nil 만 받게 될거다.

2.(solution) autorelease 이용

-(Shape*) getNewShape{
    Shape *newShape = [[Shape alloc]init];
    return [newShape autorelease];
}

이렇게 return 하기 전에 autorelease 메시지를 호출 해 주게 되면, 
외부에서 사용할 때 @autoreleasepool 블록 안에서 자유롭게 사용 하다가 블록이 끝나는 시점에 한꺼번에 해제되게 된다.

2016년 5월 12일 목요일

Objective-C 카테고리 사용 시 주의사항

카테고리 사용 용도
1.  기존에 구현 된 클래스에 대한 이해 없이 당장 필요한 기능(메소드)


// Fraction.h 파일

#import <Foundation/Foundation.h>

@interface Fraction : NSObject

@property int numerator, denominator;
// 하단의 getter setter @property 선언 만으로도 선언되어짐
//- (void) setNumerator: (int)n;  // 이렇게 선언 하면 외부에서 접근 가능
//- (void) setDenominator: (int)d;
//- (int) numerator;
//- (int) denominator;
-(void) print;

@end


// Fraction.m 파일

#import "Fraction.h"

@implementation Fraction
{
    int isStarted;
}
@synthesize numerator = _numerator, denominator = _denominator;
//{
//    int numerator;
//    int denominator;
//}

//- (void) setNumerator:(int)n
//{
//    numerator = n;
//}
//
//- (void) setDenominator:(int)d
//{
//    denominator = d;
//}
//
//- (int) numerator
//{
//    return numerator;
//}
//
//- (int) denominator
//{
//    return denominator;
//}
- (void) print  // interface부에 선언되지 않은 함수는 외부(다른소스코드파일)에서 접근 불가
{
    static int printCnt = 0;    // Fraction 클래스 인스턴스에서 1개만 존재 .
    NSLog(@"[%i] %i/%i", printCnt++, _numerator, _denominator);
}


@end


// Fraction MathOps 구현 부분

#import "Fraction.h"

@interface Fraction(MathOps)
-(Fraction*) add:(Fraction*) f;
-(Fraction*) mul:(Fraction*) f;
-(Fraction*) sub:(Fraction*) f;
-(Fraction*) div:(Fraction*) f;
@end

@implementation Fraction (MathOps)
-(Fraction*) add:(Fraction *)f{
    isStarted = 1;
    Fraction* result = [[Fraction alloc]init];
    result.numerator = (self.numerator * f.denominator) + (self.denominator * f.numerator);
    result.denominator = self.denominator * f.denominator;
    return result;
}
-(Fraction*) sub:(Fraction *)f{
    Fraction* result = [[Fraction alloc]init];
    result.numerator = (self.numerator * f.denominator) - (self.denominator * f.numerator);
    result.denominator = self.denominator * f.denominator;
    return result;
}
-(Fraction*) mul:(Fraction *)f{
    Fraction* result = [[Fraction alloc]init];
    result.numerator = self.numerator * f.numerator;
    result.denominator = self.denominator * f.denominator;
    return result;
}
-(Fraction*) div:(Fraction *)f{
    Fraction* result = [[Fraction alloc]init];
    result.numerator = self.numerator * f.denominator;
    result.denominator = self.denominator * f.numerator;
    return result;
}


@end


소스코드를 보면 Fraction.m 에서 클래스 멤버변수를 선언한 부분이 있다.
implementation 부 에서 선언 된 멤버변수는 다른 파일에 구현 된 MathOps 카테고리에서 접근 불가능 하다.
왜냐하면, 원조 Fraction 클래스에서 공개되어 있는 메소드와 멤버변수는 Fraction.h 에 선언된 것 뿐이기 때문!!

2. 메소드 오버라이딩


3. 메소드의 외부 노출 없이 사용하고 싶다.

// Fraction.h

@interface Fraction : NSObject

@end

// Fraction.m

@interface Fraction()
-(Fraction*) add:(Fraction*) f;
-(Fraction*) mul:(Fraction*) f;
-(Fraction*) sub:(Fraction*) f;
-(Fraction*) div:(Fraction*) f;
@end

@implementation Fraction 
-(Fraction*) add:(Fraction *)f{
    Fraction* result = [[Fraction alloc]init];
    return result;
}
-(Fraction*) sub:(Fraction *)f{
    Fraction* result = [[Fraction alloc]init];
    return result;
}
-(Fraction*) mul:(Fraction *)f{
    Fraction* result = [[Fraction alloc]init];
    return result;
}
-(Fraction*) div:(Fraction *)f{
    Fraction* result = [[Fraction alloc]init];
    return result;
}

@end

 이렇게 하면 add, mum, sub, div 함수는 외부 공개 없이 내부에서 자유롭게 사용 가능하다.

Objective-C 전역 변수

static int gValue;
int gValue2;

전역 변수를 선언하여 사용하는 방법은 일단 @interface 혹은 @implementation 외부에서 위에서 처럼 2가지
static을 붙이느냐, 붙이지 않느냐의 차이

가져다가 사용하는 입장에서는
extern int gValue;
extern int gValue2;
이렇게 extern 을 앞에다 붙여줘야 한다.

그럼 이제 처음으로 돌아가서
static - 선언 된 파일에서만 접근 가능
non static - 선언되지 않은 파일에서도 모두 접근 가능

2016년 5월 11일 수요일

Objective-C Memory Leak을 줄이는 초간단 습관 (set객체 할 때) - ARC가 활성화되지 않은 경우 이용

-(void)setOrigin:(XYPoint*)pt{
  origin = pt;
}

이렇게 전달 받는 XYPoint 포인터객체를 바로바로 할당하게 되면,
이전에 사용중이던 origin 포인터객체는 메모리에 상주하며 계속 점유하게 된다.

새로운 값으로 할당하기 전에 이전 사용하던 값은 해제하는 습관을 기르자.


-(void) setShape:(Shape*) shapeVal{
    if( shape){
        [shape release];
        shape = [shapeVal retain];
    }
    else{
        shape = [shapeVal retain];
    }

}

Objective-C @class 의 용법

@class XYPoint; // 외부에서 선언 클래스를 사용할때 쓰고 컴파일러로 하여금 해당 클래스의 존재 여부만 확인하기 위한 용도
                // #import 해당 파일의 내용을 전부 붙여넣는거고 차이점은, @class 어딘가에 선언되어 있으니 참조하라는 의미

                // -> 상호 #import 인한 재컴파일 하는 것을 미연에 방지하기 위함


그렇다고 해서 영원히 import를 하지 않아도 된다는 소리는 아님
 -> 실제로 해당 클래스의 구현부 내용이 필요할 때 (ex, 메소드 호출 시) import를 해줘야 함

If you say @class MyCoolClass, the compiler knows that it may see something like:
MyCoolClass *myObject;
It doesn't have to worry about anything other than MyCoolClass is a valid class, and it should reserve room for a pointer to it (really, just a pointer). Thus, in your header, @class suffices 90% of the time.
However, if you ever need to create or access myObject's members, you'll need to let the compiler know what those methods are. At this point (presumably in your implementation file), you'll need to #import "MyCoolClass.h", to tell the compiler additional information beyond just "this is a class".

2016년 5월 10일 화요일

Objective-C self 지시자의 용법


Objective-C는 C 기반에서 small talk의 개념을 적용 한 언어라서
기본적으로 모두 객체를 통해서 대화한다.

C로 작성 되어진 언어지만 단순한 함수선언과 호출이 아닌,
선언된 객체의 인스턴스의 메소드를 호출하는 방식으로 사용.

이는 객체 내부에서 메소드를 호출하는데도 예외는 아닌데 이 때 self 지시자가 사용된다.

@interface Car : NSObject
@property int wheel, doors;
-(void) accelerate;
@end

@implementation Car
@synthesize wheel = _wheel, doors = _doors;
-(void) accelerate{
    engine(); <-- 이렇게 쓰일 수 없음
    [self engine]; <--- 이렇게 쓰여야 함.

    _wheel = 3; <-- 멤버 변수는 이렇게 사용도 하지만
    self.wheel = 3; <-- 이렇게 property를 이용해서 사용할 수도 있음
}

-(void) engine{
  // 엔진 상태 점검
}
@end

Objective-C 기본 개념 사항에 대한 정리 블로그