Skip to content

Conversation

@JinUng41
Copy link
Collaborator

@JinUng41 JinUng41 commented Mar 31, 2025

👻 PULL REQUEST

📄 작업 내용

  • String의 익스텐션인 pretendardString의 리턴 타입을 NSMutableAttributedString으로 변경하였습니다.
  • NSMutableAttributedString의 익스텐션 메서드를 구현하였습니다.
  • AttributedString의 익스텐션 메서드를 구현하였습니다.
구현 내용 iPhone 13 mini
밑줄, 하이라이팅 적용된 버튼

💻 주요 코드 설명

NSMutableAttributedString의 익스텐션 메서드

  • 밑줄을 추가(전체, 일부)하는 메서드
  • 일부 텍스트의 색상을 변경하는 메서드
  • AttributedString도 마찬가지입니다.
NSMutableAttributedString+.swift
import UIKit

extension NSMutableAttributedString {
    
    // MARK: - addUnderline

    /// 전체 텍스트에 밑줄 스타일을 추가합니다.
    ///
    /// - Parameter style: 적용할 밑줄 스타일 (기본값: .single)
    /// - Returns: 메서드 체이닝을 위한 NSMutableAttributedString 객체
    ///
    /// - Note: 빈 문자열인 경우 아무 작업도 수행하지 않고 원본을 반환합니다.
    ///
    /// 사용 예시:
    /// ```swift
    /// // 기본 사용법
    /// let attributedText = NSMutableAttributedString(string: "안녕하세요")
    /// attributedText.addUnderline()
    /// label.attributedText = attributedText
    ///
    /// // pretendardString과 함께 메서드 체이닝
    /// label.attributedText = "안녕하세요".pretendardString(with: .body1).addUnderline()
    /// ```
    @discardableResult
    func addUnderline(style: NSUnderlineStyle = .single) -> NSMutableAttributedString {
        guard !string.isEmpty else {
            return self
        }
        
        addAttribute(.underlineStyle, value: style.rawValue, range: NSRange(location: 0, length: length))
        return self
    }
    
    /// 특정 텍스트에만 밑줄 스타일을 추가합니다.
    ///
    /// - Parameters:
    ///   - targetText: 밑줄을 추가할 대상 텍스트
    ///   - style: 적용할 밑줄 스타일 (기본값: .single)
    /// - Returns: 메서드 체이닝을 위한 NSMutableAttributedString 객체
    ///
    /// - Note: 빈 문자열이거나 대상 텍스트가 빈 문자열인 경우 아무 작업도 수행하지 않고 원본을 반환합니다.
    ///
    /// 사용 예시:
    /// ```swift
    /// // 기본 사용법
    /// let attributedText = NSMutableAttributedString(string: "안녕하세요 반갑습니다")
    /// attributedText.addUnderline(to: "반갑습니다")
    /// label.attributedText = attributedText
    ///
    /// // pretendardString과 함께 메서드 체이닝
    /// label.attributedText = "중요한 공지사항입니다".pretendardString(with: .head3).addUnderline(to: "중요한")
    /// ```
    @discardableResult
    func addUnderline(to targetText: String, style: NSUnderlineStyle = .single) -> NSMutableAttributedString {
        guard !string.isEmpty,
              !targetText.isEmpty
        else {
            return self
        }
        
        let range = (string as NSString).range(of: targetText)
        addAttribute(.underlineStyle, value: style.rawValue, range: range)
        return self
    }
    
    // MARK: - highlight
    
    /// 특정 텍스트의 색상을 변경합니다.
    ///
    /// - Parameters:
    ///   - textColor: 적용할 텍스트 색상
    ///   - targetText: 색상을 변경할 대상 텍스트
    /// - Returns: 메서드 체이닝을 위한 NSMutableAttributedString 객체
    ///
    /// - Note: 빈 문자열이거나 대상 텍스트가 빈 문자열인 경우 아무 작업도 수행하지 않고 원본을 반환합니다.
    ///
    /// 사용 예시:
    /// ```swift
    /// // 기본 사용법
    /// let attributedText = NSMutableAttributedString(string: "중요한 공지사항입니다")
    /// attributedText.highlight(textColor: .red, to: "중요한")
    /// label.attributedText = attributedText
    ///
    /// // pretendardString 및 다른 메서드와 함께 체이닝
    /// label.attributedText = "중요한 공지사항입니다".pretendardString(with: .body2).highlight(textColor: .red, to: "중요한")
    /// ```
    @discardableResult
    func highlight(textColor: UIColor, to targetText: String) -> NSMutableAttributedString {
        guard !string.isEmpty,
              !targetText.isEmpty
        else {
            return self
        }
        
        let range = (string as NSString).range(of: targetText)
        addAttribute(.foregroundColor, value: textColor, range: range)
        return self
    }
}

🔗 연결된 이슈

Summary by CodeRabbit

  • Chores

    • Updated project configuration to ensure correct file inclusion for enhanced text styling.
  • New Features

    • Introduced improved text styling options that allow flexible underlining and highlighting across the app.
    • Enhanced text functions now yield mutable styles, offering greater customization.
  • Refactor

    • Replaced legacy text-decoration approaches with streamlined implementations for a more consistent UI experience.
    • Simplified button title styling for improved code readability and efficiency.
  • Bug Fixes

    • Corrected method usage for applying underline styles in various components.
  • Removed Features

    • Removed the NavigationViewController class to streamline navigation handling.

@JinUng41 JinUng41 added ✨ feat 기능 또는 객체 구현 ♻️ refactor 기존 코드를 리팩토링하거나 수정하는 등 사용 (생산적인 경우) 🍻 진웅 술 한잔 가온나~ labels Mar 31, 2025
@JinUng41 JinUng41 added this to the 리팩토링 마감 milestone Mar 31, 2025
@JinUng41 JinUng41 requested a review from youz2me March 31, 2025 16:33
@JinUng41 JinUng41 self-assigned this Mar 31, 2025
@coderabbitai
Copy link

coderabbitai bot commented Mar 31, 2025

Walkthrough

The pull request updates the Xcode project file to reintroduce a previously removed file reference and add a new one. It refactors attributed string utility methods by replacing the old underline method with a new one and adding text highlighting capabilities in both AttributedString and NSMutableAttributedString extensions. Additionally, the pretendardString methods in the String extension have been updated to return mutable attributed string types. UI components now utilize these new extension methods for streamlined text styling.

Changes

File(s) Change Summary
Wable-iOS.xcodeproj/project.pbxproj Reintroduced Publisher+Driver.swift reference and added NSMutableAttributedString+.swift file reference.
Wable-iOS/.../AttributedString+.swift Added methods: addUnderline(style:), addUnderline(to:style:), and highlight(textColor:to:) in the AttributedString extension.
Wable-iOS/.../NSMutableAttributedString+.swift New file implementing an extension with methods: addUnderline(style:), addUnderline(to:style:), and highlight(textColor:to:) for NSMutableAttributedString.
Wable-iOS/.../String+.swift Updated pretendardString(with:) methods to return mutable attributed strings and simplified overload implementation.
Wable-iOS/.../(AgreementItemView.swift, RankListViewController.swift) Replaced usage of withUnderline() with addUnderline() and streamlined button configuration by using highlight(textColor:to:) for text styling.

Assessment against linked issues

Objective Addressed Explanation
Update String extension pretendardString to return a mutable attributed string [#156]
Implement NSMutableAttributedString extension with styling methods [#156]

Suggested labels

🛠️ fix

Suggested reviewers

  • youz2me

Poem

I'm a hopping rabbit coding in delight,
Updating my strings by day and through the night.
Underlines and highlights now prance in the code,
Refactors and extensions along the bumpy road.
With each new method, I twirl with endless cheer –
Here's to fresh changes, my dear coder, so near! 🐰🎉


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d42bca1 and a651c79.

📒 Files selected for processing (1)
  • Wable-iOS/Presentation/Helper/Extension/NSMutableAttributedString+.swift (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • Wable-iOS/Presentation/Helper/Extension/NSMutableAttributedString+.swift

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
Wable-iOS/Presentation/Helper/Extension/AttributedString+.swift (2)

65-79: Add error handling for when target text is not found

The method handles empty strings correctly but might benefit from improved error handling when the target text isn't found in the string.

Consider adding a comment or return value that indicates when the target text wasn't found:

func addUnderline(to targetText: String, style: NSUnderlineStyle = .single) -> AttributedString {
    guard !self.characters.isEmpty,
          !targetText.isEmpty
    else {
        return self
    }
    
    var newString = self
    if let range = newString.range(of: targetText) {
        var container = AttributeContainer()
        container.underlineStyle = style
        newString[range].mergeAttributes(container)
+    } else {
+        // Target text not found, returning original string
    }
    return newString
}

101-114: Add error handling for when target text is not found

Similar to the addUnderline(to:) method, consider improving error handling when the target text isn't found in the string.

Consider adding a comment or return value that indicates when the target text wasn't found:

func highlight(textColor: UIColor, to targetText: String) -> AttributedString {
    guard !self.characters.isEmpty,
          !targetText.isEmpty
    else {
        return self
    }
    
    var newString = self
    if let range = newString.range(of: targetText) {
        var container = AttributeContainer()
        container.foregroundColor = textColor
        newString[range].mergeAttributes(container)
+    } else {
+        // Target text not found, returning original string
    }
    return newString
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 45ab6f0 and d3cd5f7.

📒 Files selected for processing (6)
  • Wable-iOS.xcodeproj/project.pbxproj (4 hunks)
  • Wable-iOS/Presentation/Helper/Extension/AttributedString+.swift (1 hunks)
  • Wable-iOS/Presentation/Helper/Extension/NSMutableAttributedString+.swift (1 hunks)
  • Wable-iOS/Presentation/Helper/Extension/String+.swift (3 hunks)
  • Wable-iOS/Presentation/Onboarding/View/AgreementItemView.swift (1 hunks)
  • Wable-iOS/Presentation/Overview/Rank/View/RankListViewController.swift (1 hunks)
🧰 Additional context used
🧬 Code Definitions (2)
Wable-iOS/Presentation/Helper/Extension/AttributedString+.swift (1)
Wable-iOS/Presentation/Helper/Extension/NSMutableAttributedString+.swift (3)
  • addUnderline (31-39)
  • addUnderline (60-71)
  • highlight (94-105)
Wable-iOS/Presentation/Helper/Extension/NSMutableAttributedString+.swift (1)
Wable-iOS/Presentation/Helper/Extension/AttributedString+.swift (3)
  • addUnderline (31-43)
  • addUnderline (64-79)
  • highlight (100-115)
🔇 Additional comments (14)
Wable-iOS/Presentation/Onboarding/View/AgreementItemView.swift (1)

26-26: Good API update to improve text styling consistency.

The change from withUnderline() to addUnderline() aligns with the PR objective of refactoring string extensions. The new method name is more action-oriented and follows a consistent naming pattern with other text styling methods in the refactored implementation.

Wable-iOS/Presentation/Overview/Rank/View/RankListViewController.swift (1)

46-48: Excellent refactoring for improved readability and maintainability.

The implementation now uses the new extension methods to create attributed text with highlighting in a much cleaner way. This change:

  1. Simplifies the code by removing manual attribute range manipulation
  2. Improves readability with a declarative API
  3. Makes the styling more consistent with the rest of the application

The new highlight() method provides a clear, concise way to apply text styling that aligns perfectly with the PR objectives.

Wable-iOS.xcodeproj/project.pbxproj (6)

250-250: File reintroduced to support UI component updates.

The Publisher+Driver.swift file has been reintroduced to the project, which is necessary to support the string extension refactoring mentioned in the PR objectives.


255-255: New extension file added for attributed string enhancements.

The NSMutableAttributedString+.swift file has been added to the project, which aligns with the PR objective of adding new extension methods for NSMutableAttributedString.


503-503: File reference added properly.

The file reference for Publisher+Driver.swift has been correctly added to the project, ensuring it's properly tracked in the project structure.


508-508: New extension file reference added correctly.

The file reference for NSMutableAttributedString+.swift has been properly added to the project structure, which is needed for the new string extension functionality.


1608-1609: Extensions organized in a logical order.

The new NSMutableAttributedString+.swift extension has been placed alongside the existing AttributedString+.swift in the Extension group, which maintains a consistent organization of related extension files.


2072-2072: New extension file included in build phases.

The NSMutableAttributedString+.swift file has been correctly included in the compilation sources, ensuring it will be built with the project.

Wable-iOS/Presentation/Helper/Extension/String+.swift (4)

14-18: Documentation updated correctly to reflect return type change

The documentation comments have been correctly updated to reflect that the method now returns a NSMutableAttributedString instead of an NSAttributedString.


24-24: Function signature appropriately modified

The function signature has been updated to return NSMutableAttributedString, which aligns with the PR objectives of modifying the return type.


36-36: Return statement correctly updated

The implementation now directly constructs and returns a NSMutableAttributedString instead of an NSAttributedString, which is consistent with the updated function signature.


52-52: Code simplification

The implementation has been improved by directly constructing the AttributedString from the result of the updated pretendardString method, eliminating unnecessary intermediate variables.

Wable-iOS/Presentation/Helper/Extension/AttributedString+.swift (1)

11-43: Well-implemented underline method for the entire text

The addUnderline method is well-implemented with proper documentation, error handling for empty strings, and an appropriate use of the @discardableResult attribute. The implementation correctly handles AttributedString as a value type by creating a new string rather than modifying in place.

Wable-iOS/Presentation/Helper/Extension/NSMutableAttributedString+.swift (1)

8-39: Well-documented underline method with proper implementation

The addUnderline method for NSMutableAttributedString is well-documented with clear usage examples and proper error handling for empty strings. The @discardableResult attribute is used appropriately to support method chaining.

Copy link
Member

@youz2me youz2me left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨습니닷 생일까지 열일을 ㅜㅜ

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

문서 작성 굿입니닷!!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감사합니다!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

헉 NSMutableAttributedString랑 AttributedString 둘다 되어있군요


lazy var infoButton: UIButton = UIButton(configuration: .plain()).then {
$0.configuration?.attributedTitle = "보러가기".pretendardString(with: .body4).withUnderline()
$0.configuration?.attributedTitle = "보러가기".pretendardString(with: .body4).addUnderline()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅎㅎ 감사합니다 ~~!!!!

@github-project-automation github-project-automation bot moved this to In Review in Wable-iOS Mar 31, 2025
@JinUng41 JinUng41 merged commit 26c050b into develop Apr 1, 2025
1 check passed
@JinUng41 JinUng41 deleted the refactor/#156-string-extension branch April 1, 2025 02:53
@github-project-automation github-project-automation bot moved this from In Review to Done in Wable-iOS Apr 1, 2025
youz2me pushed a commit that referenced this pull request Oct 26, 2025
[Refactor] String 익스텐션 수정
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ feat 기능 또는 객체 구현 ♻️ refactor 기존 코드를 리팩토링하거나 수정하는 등 사용 (생산적인 경우) 🍻 진웅 술 한잔 가온나~

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[Refactor] String 익스텐션 수정 및 NSMutableAttributedString 익스텐션 구현

3 participants