-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Pigbag] Step04 - 2 image추가 로직, View Factory 리팩토링 #106
base: pigbag
Are you sure you want to change the base?
Conversation
let key = Point(x: x, y: y) | ||
func addRectangle() -> PlaneRectangle{ | ||
let rect = RectangleFactory.makePlaneRectangle() | ||
rectangles.append(rect) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Plane이 생성의 역할을 하는게 맞다고 생각해 Factory를 이용해 생성을 했습니다.
다만, 이렇게 인스턴스를 이용한게 아닌 Static메서드를 이용해서 생성을 하는 경우 Plane은 Factory를 몰라도 된다
가
성립이 되는지는 잘 모르겠습니다..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Static 메소드를 사용하면 오히려 더 RectangleFactory 타입과 분리하기 어려워지죠. 다형성도 동작하지 않으니까요
그래서 RectangleFactory를 대신할 프로토콜로 접근해보는 게 좋습니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
프로토콜을 사용해서 다시 시도해보겠습니다!
self?.image.addRectangle(imageData: data) | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
한번에 여러 사진을 가지고 오기위해 함수들을 이용해서 데이터를 가지고 오려 시도했습니다.
let x = Double(touch.location(in: self.view).x) | ||
let y = Double(touch.location(in: self.view).y) | ||
let point = Point(x: x, y: y) | ||
plane.findSeletedRectangle(point: point) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
사각형의 origin대신 좌표값을 넘겨주는 것으로 수정했습니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Plane과 Image의 관계를 꼭 개선해보셨으면 합니다.
static func makePlaneRectangleView(sourceRectangle: Rectangleable) -> UIView { | ||
let source = sourceRectangle as! PlaneRectangle | ||
let rectangleView = UIView(frame: .zero) | ||
rectangleView.frame = setUpFrameWithRectangle(source) | ||
rectangleView.backgroundColor = setupBackgroundColor(rgb: source.rgb, alpha: source.alpha) | ||
return rectangleView | ||
} | ||
|
||
//IamgeView | ||
static func makeImageRectangleView(sourceRectangle: Rectangleable) -> UIImageView { | ||
let source = sourceRectangle as! ImageRectangle | ||
let rectangleView = UIImageView(frame: .zero) | ||
rectangleView.frame = setUpFrameWithRectangle(source) | ||
rectangleView.image = setupImage(imageData: source.imageData) | ||
return rectangleView | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
다음에는 여기서 return 타입을 추상화해 보는 것도 좋은 시도가 될 것 같습니다.
UIView와 UIImage를 생성하지만 받는 쪽에서 구체 타입을 최소한으로 알고 다룰 수 있도록 하는거죠.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
넵 !시도해보겠습니다
import PhotosUI | ||
|
||
typealias RectangleView = UIView | ||
typealias imageURLData = Data |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
타입 이름은 Alias를 해도 대문자로 표기해주세요
private var plane = Plane() | ||
private var image = Image() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아직 Image라는 타입을 살펴본 건 아니지만 local reasoning을 해보자면, plane과 대등하게 이미지만 관리하는 타입처럼 보입니다.
Plane에서 통합해서 관리하는 것은 어떨까요?
private func configureImageNotificationCenter() { | ||
NotificationCenter.default.addObserver( | ||
self, | ||
selector:#selector(addImageRectangleView), | ||
name: Image.NotificationName.didAddRectangle, | ||
object: image) | ||
|
||
NotificationCenter.default.addObserver( | ||
self, | ||
selector: #selector(findSelectedImageRectangle), | ||
name: Image.NotificationName.didFindRectangle, | ||
object: image ) | ||
|
||
NotificationCenter.default.addObserver( | ||
self, | ||
selector: #selector(changeIamgeAlpha), | ||
name: Image.NotificationName.didchangeRectangleAlpha, | ||
object: image ) | ||
|
||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기만 들여쓰기가 좀 다르네요.
guard let newImageRectangle = notification.userInfo?[Image.UserInfoKey.addedRectangle] as? ImageRectangle else { return } | ||
|
||
DispatchQueue.main.async { [weak self] in | ||
guard let self = self else { return } | ||
let rectangleView = RectangleViewFactory.makeImageRectangleView(sourceRectangle: newImageRectangle) | ||
self.imageRectangleViews[newImageRectangle.imageData] = rectangleView | ||
|
||
self.view.addSubview(rectangleView) | ||
self.bringButtonViewToFront() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이렇게 되면 상당 부분 addRectangleView()와 비슷한 코드가 중복되지 않나요?
RectangleViewFactory도 같이 쓰고 self.view.addSubview()도 동일한 것 같은데, 일반화시킬 수 있는 부분은 없을까요?
seletedRectangleView?.layer.borderWidth = .zero | ||
|
||
guard let seletedRectangle = notification.userInfo?[Image.UserInfoKey.foundRectangle] as? ImageRectangle else { return } | ||
|
||
let rectangleView = self.imageRectangleViews[seletedRectangle.imageData] | ||
self.seletedRectangleView = rectangleView | ||
|
||
seletedRectangleView?.layer.borderWidth = 2.0 | ||
seletedRectangleView?.layer.borderColor = UIColor.blue.cgColor | ||
seletedRectangleView?.layer.borderColor = UIColor.red.cgColor | ||
|
||
self.detailView.alphaLabel.text = "\(seletedRectangle.alpha?.value ?? 0.0)" | ||
self.detailView.alphaSlider.value = seletedRectangle.alpha?.value ?? 0.0 | ||
self.detailView.alphaLabel.text = "\(seletedRectangle.alpha.value)" | ||
self.detailView.alphaSlider.value = seletedRectangle.alpha.value | ||
|
||
self.detailView.backgroundColorButton.setTitle("\(seletedRectangle.rgb?.hexValue ?? "")", for: .normal) | ||
self.detailView.backgroundColorButton.setTitle("NONE", for: .normal) | ||
self.detailView.backgroundColorButton.alpha = 0.3 | ||
self.detailView.backgroundColorButton.isEnabled = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 함수도 findSelectedRectangle와 상당부분 비슷하지 않나요?
class Image { | ||
|
||
private var rectangles:[Point:ImageRectangle] = [:] | ||
private var selectedRectangle:ImageRectangle? | ||
private var imageRectangles:[ImageRectangle] = [] | ||
private var selectedImageRectangle:ImageRectangle? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아래 코드들을 자세히 보지 않아도 상당 부분 Plane과 겹치는 게 보이는 것 같습니다.
PlaneRectangle을 따로 두지 않고 ImageRectangle을 추상화해서 한꺼번에 다루도록 개선해보세요
let key = Point(x: x, y: y) | ||
func addRectangle() -> PlaneRectangle{ | ||
let rect = RectangleFactory.makePlaneRectangle() | ||
rectangles.append(rect) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Static 메소드를 사용하면 오히려 더 RectangleFactory 타입과 분리하기 어려워지죠. 다형성도 동작하지 않으니까요
그래서 RectangleFactory를 대신할 프로토콜로 접근해보는 게 좋습니다.
키워드: UTType, NSItemProviderReading, MiME
고민 및 해결
UIView를 상속하는 Custom View를 만들때 생성자에는 우리가 원하는 값 모두를 매개변수에 넣을 수 없기때문에(required init 때문에)
어떻게 하면 View를 초기에 생성할때 모든 속성을 다 주고 만들 수 있을까?
고민이 있었습니다.고민 끝에, 결국 생성을 담당하는 곳은
Factory
이기에 처리를 Factory에 맡겨야 겠다는 생각이 들었고,새로운 타입을 만들고 억지로 Protocol을 만들어서 엮기보다는
UIView자체를 이용
하자는 결론에 이르렀습니다.Factory에서 UIView를 리턴을 하되 함수의 매개변수에는 모델들이 채택하는 프로토콜을 넣었습니다.
적절한 함수명과함께 static메서드 별로 다른 사각형뷰를 리턴을 한다면 각각의 타입을 만든것이랑 동일 한 효과를 낼수 있다고 생각했습니다.
이후, ViewController에서 사용할때 typealias를 이용해서 UIView라는 네이밍보다는 좀더 구체적인 네이밍을 주려고 시도했습니다.
고민 및 시도
이번 Step을 진행하면서 기존에 있던 로직과 겹치는 부분이 상당수 있다는 것을 확인했습니다.(뷰에서 사각형 선택,테두리바꾸기 등등..)
현재 제 로직에서 위처럼 부분들을 추상화 하려면 Dictaionary의 Key값을 프로토콜과 같은 형태로 바꾸어야 할것 같아 시도 해봤으나
잘 되지 않았습니다. 조금 더 고민해야 될것 같습니다.