diff --git a/Session/Conversations/Context Menu/ContextMenuVC+Action.swift b/Session/Conversations/Context Menu/ContextMenuVC+Action.swift index 901e5e50c..e83465073 100644 --- a/Session/Conversations/Context Menu/ContextMenuVC+Action.swift +++ b/Session/Conversations/Context Menu/ContextMenuVC+Action.swift @@ -6,38 +6,38 @@ extension ContextMenuVC { let title: String let work: () -> Void - static func reply(_ viewItem: ConversationViewItem, _ delegate: ContextMenuActionDelegate) -> Action { + static func reply(_ viewItem: ConversationViewItem, _ delegate: ContextMenuActionDelegate?) -> Action { let title = "Reply" - return Action(icon: UIImage(named: "ic_reply")!, title: title) { delegate.reply(viewItem) } + return Action(icon: UIImage(named: "ic_reply")!, title: title) { delegate?.reply(viewItem) } } - static func copy(_ viewItem: ConversationViewItem, _ delegate: ContextMenuActionDelegate) -> Action { + static func copy(_ viewItem: ConversationViewItem, _ delegate: ContextMenuActionDelegate?) -> Action { let title = "Copy" - return Action(icon: UIImage(named: "ic_copy")!, title: title) { delegate.copy(viewItem) } + return Action(icon: UIImage(named: "ic_copy")!, title: title) { delegate?.copy(viewItem) } } - static func copySessionID(_ viewItem: ConversationViewItem, _ delegate: ContextMenuActionDelegate) -> Action { + static func copySessionID(_ viewItem: ConversationViewItem, _ delegate: ContextMenuActionDelegate?) -> Action { let title = "Copy Session ID" - return Action(icon: UIImage(named: "ic_copy")!, title: title) { delegate.copySessionID(viewItem) } + return Action(icon: UIImage(named: "ic_copy")!, title: title) { delegate?.copySessionID(viewItem) } } - static func delete(_ viewItem: ConversationViewItem, _ delegate: ContextMenuActionDelegate) -> Action { + static func delete(_ viewItem: ConversationViewItem, _ delegate: ContextMenuActionDelegate?) -> Action { let title = "Delete" - return Action(icon: UIImage(named: "ic_trash")!, title: title) { delegate.delete(viewItem) } + return Action(icon: UIImage(named: "ic_trash")!, title: title) { delegate?.delete(viewItem) } } - static func save(_ viewItem: ConversationViewItem, _ delegate: ContextMenuActionDelegate) -> Action { + static func save(_ viewItem: ConversationViewItem, _ delegate: ContextMenuActionDelegate?) -> Action { let title = "Save" - return Action(icon: UIImage(named: "ic_download")!, title: title) { delegate.save(viewItem) } + return Action(icon: UIImage(named: "ic_download")!, title: title) { delegate?.save(viewItem) } } - static func ban(_ viewItem: ConversationViewItem, _ delegate: ContextMenuActionDelegate) -> Action { + static func ban(_ viewItem: ConversationViewItem, _ delegate: ContextMenuActionDelegate?) -> Action { let title = "Ban User" - return Action(icon: UIImage(named: "ic_block")!, title: title) { delegate.ban(viewItem) } + return Action(icon: UIImage(named: "ic_block")!, title: title) { delegate?.ban(viewItem) } } } - static func actions(for viewItem: ConversationViewItem, delegate: ContextMenuActionDelegate) -> [Action] { + static func actions(for viewItem: ConversationViewItem, delegate: ContextMenuActionDelegate?) -> [Action] { func isReplyingAllowed() -> Bool { guard let message = viewItem.interaction as? TSOutgoingMessage else { return true } switch message.messageState { @@ -71,7 +71,7 @@ extension ContextMenuVC { } // MARK: Delegate -protocol ContextMenuActionDelegate { +protocol ContextMenuActionDelegate : class { func reply(_ viewItem: ConversationViewItem) func copy(_ viewItem: ConversationViewItem) diff --git a/Session/Conversations/Context Menu/ContextMenuVC.swift b/Session/Conversations/Context Menu/ContextMenuVC.swift index fc2252f7d..13e923677 100644 --- a/Session/Conversations/Context Menu/ContextMenuVC.swift +++ b/Session/Conversations/Context Menu/ContextMenuVC.swift @@ -3,8 +3,8 @@ final class ContextMenuVC : UIViewController { private let snapshot: UIView private let viewItem: ConversationViewItem private let frame: CGRect - private let delegate: ContextMenuActionDelegate private let dismiss: () -> Void + private weak var delegate: ContextMenuActionDelegate? // MARK: UI Components private lazy var blurView = UIVisualEffectView(effect: nil) diff --git a/Session/Conversations/Input View/ExpandingAttachmentsButton.swift b/Session/Conversations/Input View/ExpandingAttachmentsButton.swift index 33dfae446..a42f4488e 100644 --- a/Session/Conversations/Input View/ExpandingAttachmentsButton.swift +++ b/Session/Conversations/Input View/ExpandingAttachmentsButton.swift @@ -1,6 +1,6 @@ final class ExpandingAttachmentsButton : UIView, InputViewButtonDelegate { - private let delegate: ExpandingAttachmentsButtonDelegate + private weak var delegate: ExpandingAttachmentsButtonDelegate? private var isExpanded = false { didSet { expandOrCollapse() } } // MARK: Constraints @@ -22,7 +22,7 @@ final class ExpandingAttachmentsButton : UIView, InputViewButtonDelegate { lazy var mainButtonContainer = container(for: mainButton) // MARK: Lifecycle - init(delegate: ExpandingAttachmentsButtonDelegate) { + init(delegate: ExpandingAttachmentsButtonDelegate?) { self.delegate = delegate super.init(frame: CGRect.zero) setUpViewHierarchy() @@ -93,10 +93,10 @@ final class ExpandingAttachmentsButton : UIView, InputViewButtonDelegate { // MARK: Interaction func handleInputViewButtonTapped(_ inputViewButton: InputViewButton) { - if inputViewButton == gifButton { delegate.handleGIFButtonTapped(); isExpanded = false } - if inputViewButton == documentButton { delegate.handleDocumentButtonTapped(); isExpanded = false } - if inputViewButton == libraryButton { delegate.handleLibraryButtonTapped(); isExpanded = false } - if inputViewButton == cameraButton { delegate.handleCameraButtonTapped(); isExpanded = false } + if inputViewButton == gifButton { delegate?.handleGIFButtonTapped(); isExpanded = false } + if inputViewButton == documentButton { delegate?.handleDocumentButtonTapped(); isExpanded = false } + if inputViewButton == libraryButton { delegate?.handleLibraryButtonTapped(); isExpanded = false } + if inputViewButton == cameraButton { delegate?.handleCameraButtonTapped(); isExpanded = false } if inputViewButton == mainButton { isExpanded = !isExpanded } } @@ -112,7 +112,7 @@ final class ExpandingAttachmentsButton : UIView, InputViewButtonDelegate { } // MARK: Delegate -protocol ExpandingAttachmentsButtonDelegate { +protocol ExpandingAttachmentsButtonDelegate : class { func handleGIFButtonTapped() func handleDocumentButtonTapped() diff --git a/Session/Conversations/Input View/InputTextView.swift b/Session/Conversations/Input View/InputTextView.swift index e39e1ddfe..276072e69 100644 --- a/Session/Conversations/Input View/InputTextView.swift +++ b/Session/Conversations/Input View/InputTextView.swift @@ -1,6 +1,6 @@ public final class InputTextView : UITextView, UITextViewDelegate { - private let snDelegate: InputTextViewDelegate + private weak var snDelegate: InputTextViewDelegate? private let maxWidth: CGFloat private lazy var heightConstraint = self.set(.height, to: minHeight) @@ -60,7 +60,7 @@ public final class InputTextView : UITextView, UITextViewDelegate { } private func handleTextChanged() { - defer { snDelegate.inputTextViewDidChangeContent(self) } + defer { snDelegate?.inputTextViewDidChangeContent(self) } placeholderLabel.isHidden = !text.isEmpty let height = frame.height let size = sizeThatFits(CGSize(width: maxWidth, height: .greatestFiniteMagnitude)) @@ -69,12 +69,12 @@ public final class InputTextView : UITextView, UITextViewDelegate { let newHeight = size.height.clamp(minHeight, maxHeight) guard newHeight != height else { return } heightConstraint.constant = newHeight - snDelegate.inputTextViewDidChangeSize(self) + snDelegate?.inputTextViewDidChangeSize(self) } } // MARK: Delegate -protocol InputTextViewDelegate { +protocol InputTextViewDelegate : class { func inputTextViewDidChangeSize(_ inputTextView: InputTextView) func inputTextViewDidChangeContent(_ inputTextView: InputTextView) diff --git a/Session/Conversations/Input View/InputView.swift b/Session/Conversations/Input View/InputView.swift index 9525a7b6c..798c4a22e 100644 --- a/Session/Conversations/Input View/InputView.swift +++ b/Session/Conversations/Input View/InputView.swift @@ -1,6 +1,6 @@ final class InputView : UIView, InputViewButtonDelegate, InputTextViewDelegate, QuoteViewDelegate, LinkPreviewViewDelegate, MentionSelectionViewDelegate { - private let delegate: InputViewDelegate + private weak var delegate: InputViewDelegate? var quoteDraftInfo: (model: OWSQuotedReplyModel, isOutgoing: Bool)? { didSet { handleQuoteDraftChanged() } } var linkPreviewInfo: (url: String, draft: OWSLinkPreviewDraft?)? private var voiceMessageRecordingView: VoiceMessageRecordingView? @@ -135,7 +135,7 @@ final class InputView : UIView, InputViewButtonDelegate, InputTextViewDelegate, sendButton.isHidden = !hasText voiceMessageButtonContainer.isHidden = hasText autoGenerateLinkPreviewIfPossible() - delegate.inputTextViewDidChangeContent(inputTextView) + delegate?.inputTextViewDidChangeContent(inputTextView) } // We want to show either a link preview or a quote draft, but never both at the same time. When trying to @@ -164,7 +164,7 @@ final class InputView : UIView, InputViewButtonDelegate, InputTextViewDelegate, let userDefaults = UserDefaults.standard if !OWSLinkPreview.allPreviewUrls(forMessageBodyText: text).isEmpty && !SSKPreferences.areLinkPreviewsEnabled && !userDefaults[.hasSeenLinkPreviewSuggestion] { - delegate.showLinkPreviewSuggestionModal() + delegate?.showLinkPreviewSuggestionModal() userDefaults[.hasSeenLinkPreviewSuggestion] = true return } @@ -235,12 +235,12 @@ final class InputView : UIView, InputViewButtonDelegate, InputTextViewDelegate, } func handleInputViewButtonTapped(_ inputViewButton: InputViewButton) { - if inputViewButton == sendButton { delegate.handleSendButtonTapped() } + if inputViewButton == sendButton { delegate?.handleSendButtonTapped() } } func handleInputViewButtonLongPressBegan(_ inputViewButton: InputViewButton) { guard inputViewButton == voiceMessageButton else { return } - delegate.startVoiceMessageRecording() + delegate?.startVoiceMessageRecording() showVoiceMessageUI() } @@ -257,7 +257,7 @@ final class InputView : UIView, InputViewButtonDelegate, InputTextViewDelegate, } func handleQuoteViewCancelButtonTapped() { - delegate.handleQuoteViewCancelButtonTapped() + delegate?.handleQuoteViewCancelButtonTapped() } override func resignFirstResponder() -> Bool { @@ -326,7 +326,7 @@ final class InputView : UIView, InputViewButtonDelegate, InputTextViewDelegate, } func handleMentionSelected(_ mention: Mention, from view: MentionSelectionView) { - delegate.handleMentionSelected(mention, from: view) + delegate?.handleMentionSelected(mention, from: view) } // MARK: Convenience @@ -341,7 +341,7 @@ final class InputView : UIView, InputViewButtonDelegate, InputTextViewDelegate, } // MARK: Delegate -protocol InputViewDelegate : ExpandingAttachmentsButtonDelegate, VoiceMessageRecordingViewDelegate { +protocol InputViewDelegate : class, ExpandingAttachmentsButtonDelegate, VoiceMessageRecordingViewDelegate { func showLinkPreviewSuggestionModal() func handleSendButtonTapped() diff --git a/Session/Conversations/Input View/InputViewButton.swift b/Session/Conversations/Input View/InputViewButton.swift index 480ff3cc0..92707c7fc 100644 --- a/Session/Conversations/Input View/InputViewButton.swift +++ b/Session/Conversations/Input View/InputViewButton.swift @@ -2,7 +2,7 @@ final class InputViewButton : UIView { private let icon: UIImage private let isSendButton: Bool - private let delegate: InputViewButtonDelegate + private weak var delegate: InputViewButtonDelegate? private let hasOpaqueBackground: Bool private lazy var widthConstraint = set(.width, to: InputViewButton.size) private lazy var heightConstraint = set(.height, to: InputViewButton.size) @@ -103,22 +103,22 @@ final class InputViewButton : UIView { longPressTimer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false, block: { [weak self] _ in guard let self = self else { return } self.isLongPress = true - self.delegate.handleInputViewButtonLongPressBegan(self) + self.delegate?.handleInputViewButtonLongPressBegan(self) }) } override func touchesMoved(_ touches: Set, with event: UIEvent?) { if isLongPress { - delegate.handleInputViewButtonLongPressMoved(self, with: touches.first!) + delegate?.handleInputViewButtonLongPressMoved(self, with: touches.first!) } } override func touchesEnded(_ touches: Set, with event: UIEvent?) { collapse() if !isLongPress { - delegate.handleInputViewButtonTapped(self) + delegate?.handleInputViewButtonTapped(self) } else { - delegate.handleInputViewButtonLongPressEnded(self, with: touches.first!) + delegate?.handleInputViewButtonLongPressEnded(self, with: touches.first!) } invalidateLongPressIfNeeded() } @@ -135,7 +135,7 @@ final class InputViewButton : UIView { } // MARK: Delegate -protocol InputViewButtonDelegate { +protocol InputViewButtonDelegate : class { func handleInputViewButtonTapped(_ inputViewButton: InputViewButton) func handleInputViewButtonLongPressBegan(_ inputViewButton: InputViewButton) diff --git a/Session/Conversations/Input View/MentionSelectionView.swift b/Session/Conversations/Input View/MentionSelectionView.swift index 26e31dd89..5978818bc 100644 --- a/Session/Conversations/Input View/MentionSelectionView.swift +++ b/Session/Conversations/Input View/MentionSelectionView.swift @@ -9,7 +9,7 @@ final class MentionSelectionView : UIView, UITableViewDataSource, UITableViewDel var openGroupServer: String? var openGroupChannel: UInt64? var openGroupRoom: String? - var delegate: MentionSelectionViewDelegate? + weak var delegate: MentionSelectionViewDelegate? // MARK: Components lazy var tableView: UITableView = { // TODO: Make this private @@ -177,7 +177,7 @@ private extension MentionSelectionView { // MARK: - Delegate -protocol MentionSelectionViewDelegate { +protocol MentionSelectionViewDelegate : class { func handleMentionSelected(_ mention: Mention, from view: MentionSelectionView) } diff --git a/Session/Conversations/Input View/VoiceMessageRecordingView.swift b/Session/Conversations/Input View/VoiceMessageRecordingView.swift index bd558394f..c6b54accb 100644 --- a/Session/Conversations/Input View/VoiceMessageRecordingView.swift +++ b/Session/Conversations/Input View/VoiceMessageRecordingView.swift @@ -1,7 +1,7 @@ final class VoiceMessageRecordingView : UIView { private let voiceMessageButtonFrame: CGRect - private let delegate: VoiceMessageRecordingViewDelegate + private weak var delegate: VoiceMessageRecordingViewDelegate? private lazy var slideToCancelStackViewRightConstraint = slideToCancelStackView.pin(.right, to: .right, of: self) private lazy var slideToCancelLabelCenterHorizontalConstraint = slideToCancelLabel.center(.horizontal, in: self) private lazy var pulseViewWidthConstraint = pulseView.set(.width, to: VoiceMessageRecordingView.circleSize) @@ -115,7 +115,7 @@ final class VoiceMessageRecordingView : UIView { private static let lockViewHitMargin: CGFloat = 40 // MARK: Lifecycle - init(voiceMessageButtonFrame: CGRect, delegate: VoiceMessageRecordingViewDelegate) { + init(voiceMessageButtonFrame: CGRect, delegate: VoiceMessageRecordingViewDelegate?) { self.voiceMessageButtonFrame = voiceMessageButtonFrame self.delegate = delegate super.init(frame: CGRect.zero) @@ -269,7 +269,7 @@ final class VoiceMessageRecordingView : UIView { func handleLongPressEnded(at location: CGPoint) { if pulseView.frame.contains(location) { - delegate.endVoiceMessageRecording() + delegate?.endVoiceMessageRecording() } else if isValidLockViewLocation(location) { let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleCircleViewTap)) circleView.addGestureRecognizer(tapGestureRecognizer) @@ -282,16 +282,16 @@ final class VoiceMessageRecordingView : UIView { // Do nothing }) } else { - delegate.cancelVoiceMessageRecording() + delegate?.cancelVoiceMessageRecording() } } @objc private func handleCircleViewTap() { - delegate.endVoiceMessageRecording() + delegate?.endVoiceMessageRecording() } @objc private func handleCancelButtonTapped() { - delegate.cancelVoiceMessageRecording() + delegate?.cancelVoiceMessageRecording() } // MARK: Convenience @@ -397,7 +397,7 @@ extension VoiceMessageRecordingView { } // MARK: Delegate -protocol VoiceMessageRecordingViewDelegate { +protocol VoiceMessageRecordingViewDelegate : class { func startVoiceMessageRecording() func endVoiceMessageRecording() diff --git a/Session/Conversations/Message Cells/MessageCell.swift b/Session/Conversations/Message Cells/MessageCell.swift index 733afa3ce..69f4dce25 100644 --- a/Session/Conversations/Message Cells/MessageCell.swift +++ b/Session/Conversations/Message Cells/MessageCell.swift @@ -1,7 +1,7 @@ import UIKit class MessageCell : UITableViewCell { - var delegate: MessageCellDelegate? + weak var delegate: MessageCellDelegate? var viewItem: ConversationViewItem? { didSet { update() } } // MARK: Settings @@ -48,7 +48,7 @@ class MessageCell : UITableViewCell { } } -protocol MessageCellDelegate { +protocol MessageCellDelegate : class { var lastSearchedText: String? { get } func getMediaCache() -> NSCache diff --git a/Session/Conversations/Views & Modals/ConversationTitleView.swift b/Session/Conversations/Views & Modals/ConversationTitleView.swift index 94fcb9242..b3e8f7524 100644 --- a/Session/Conversations/Views & Modals/ConversationTitleView.swift +++ b/Session/Conversations/Views & Modals/ConversationTitleView.swift @@ -1,7 +1,7 @@ final class ConversationTitleView : UIView { private let thread: TSThread - var delegate: ConversationTitleViewDelegate? + weak var delegate: ConversationTitleViewDelegate? override var intrinsicContentSize: CGSize { return UIView.layoutFittingExpandedSize @@ -121,7 +121,7 @@ final class ConversationTitleView : UIView { } // MARK: Delegate -protocol ConversationTitleViewDelegate { +protocol ConversationTitleViewDelegate : class { func handleTitleViewTapped() } diff --git a/Session/Conversations/Views & Modals/ScrollToBottomButton.swift b/Session/Conversations/Views & Modals/ScrollToBottomButton.swift index cdaea97c1..684537b84 100644 --- a/Session/Conversations/Views & Modals/ScrollToBottomButton.swift +++ b/Session/Conversations/Views & Modals/ScrollToBottomButton.swift @@ -1,6 +1,6 @@ final class ScrollToBottomButton : UIView { - private let delegate: ScrollToBottomButtonDelegate + private weak var delegate: ScrollToBottomButtonDelegate? // MARK: Settings private static let size: CGFloat = 40 @@ -57,11 +57,11 @@ final class ScrollToBottomButton : UIView { // MARK: Interaction @objc private func handleTap() { - delegate.handleScrollToBottomButtonTapped() + delegate?.handleScrollToBottomButtonTapped() } } -protocol ScrollToBottomButtonDelegate { + protocol ScrollToBottomButtonDelegate : class { func handleScrollToBottomButtonTapped() }