Skip to content

Commit e3727d8

Browse files
committed
- Fixed a few memory leaks (Not tested much)
1 parent 615ea49 commit e3727d8

9 files changed

Lines changed: 128 additions & 74 deletions

File tree

Demo/Swift_Demo/Cell/ImageSwitchTableViewCell.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2222
// THE SOFTWARE.
2323

24+
import UIKit
25+
2426
class ImageSwitchTableViewCell: SwitchTableViewCell {
2527

2628
@IBOutlet var arrowImageView: UIImageView!

IQKeyboardManagerSwift/Configuration/IQActiveConfiguration.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,13 @@ internal final class IQActiveConfiguration {
8787
}, completion: nil)
8888
}
8989
}
90+
} else if textFieldViewInfo == nil, let rootControllerConfiguration = rootControllerConfiguration {
91+
if rootControllerConfiguration.hasChanged {
92+
animate(alongsideTransition: {
93+
rootControllerConfiguration.restore()
94+
}, completion: nil)
95+
}
96+
self.rootControllerConfiguration = nil
9097
}
9198
}
9299

IQKeyboardManagerSwift/IQKeyboardManager/IQKeyboardManager+Toolbar.swift

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -230,12 +230,7 @@ public extension IQKeyboardManager {
230230
/** Remove any toolbar if it is IQToolbar. */
231231
internal func removeToolbarIfRequired() { // (Bug ID: #18)
232232

233-
guard let siblings: [UIView] = responderViews(), !siblings.isEmpty,
234-
let textField: UIView = activeConfiguration.textFieldViewInfo?.textFieldView,
235-
textField.responds(to: #selector(setter: UITextField.inputAccessoryView)),
236-
textField.inputAccessoryView == nil ||
237-
textField.inputAccessoryView?.tag == IQKeyboardManager.kIQPreviousNextButtonToolbarTag ||
238-
textField.inputAccessoryView?.tag == IQKeyboardManager.kIQDoneButtonToolbarTag else {
233+
guard let siblings: [UIView] = responderViews(), !siblings.isEmpty else {
239234
return
240235
}
241236

@@ -245,26 +240,29 @@ public extension IQKeyboardManager {
245240
showLog("Found \(siblings.count) responder sibling(s)")
246241

247242
for view in siblings {
248-
if let toolbar: IQToolbar = view.inputAccessoryView as? IQToolbar {
243+
removeToolbarIfRequired(of: view)
244+
}
249245

250-
// setInputAccessoryView: check (Bug ID: #307)
251-
if view.responds(to: #selector(setter: UITextField.inputAccessoryView)),
252-
toolbar.tag == IQKeyboardManager.kIQDoneButtonToolbarTag ||
253-
toolbar.tag == IQKeyboardManager.kIQPreviousNextButtonToolbarTag {
246+
let elapsedTime: CFTimeInterval = CACurrentMediaTime() - startTime
247+
showLog("<<<<< \(#function) ended: \(elapsedTime) seconds <<<<<", indentation: -1)
248+
}
254249

255-
if let textField: UITextField = view as? UITextField {
256-
textField.inputAccessoryView = nil
257-
} else if let textView: UITextView = view as? UITextView {
258-
textView.inputAccessoryView = nil
259-
}
250+
/** Remove any toolbar if it is IQToolbar. */
251+
internal func removeToolbarIfRequired(of view: UIView) { // (Bug ID: #18)
260252

261-
view.reloadInputViews()
262-
}
263-
}
253+
guard view.responds(to: #selector(setter: UITextField.inputAccessoryView)),
254+
let toolbar: IQToolbar = view.inputAccessoryView as? IQToolbar,
255+
toolbar.tag == IQKeyboardManager.kIQPreviousNextButtonToolbarTag ||
256+
toolbar.tag == IQKeyboardManager.kIQDoneButtonToolbarTag else {
257+
return
264258
}
265259

266-
let elapsedTime: CFTimeInterval = CACurrentMediaTime() - startTime
267-
showLog("<<<<< \(#function) ended: \(elapsedTime) seconds <<<<<", indentation: -1)
260+
// setInputAccessoryView: check (Bug ID: #307)
261+
if let textField: UITextField = view as? UITextField {
262+
textField.inputAccessoryView = nil
263+
} else if let textView: UITextView = view as? UITextView {
264+
textView.inputAccessoryView = nil
265+
}
268266
}
269267

270268
/** reloadInputViews to reload toolbar buttons enable/disable state on the fly Enhancement ID #434. */

IQKeyboardManagerSwift/IQKeyboardManager/IQKeyboardManager+UIKeyboardNotification.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ internal extension IQKeyboardManager {
129129

130130
// Removing gesture recognizer (Enhancement ID: #14)
131131
textFieldView.window?.removeGestureRecognizer(resignFirstResponderGesture)
132-
132+
removeToolbarIfRequired()
133133
do {
134134
if let startingConfiguration = startingTextViewConfiguration,
135135
startingConfiguration.hasChanged {

IQKeyboardManagerSwift/IQKeyboardManagerCompatible/IQKeyboardManagerCompatible.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ import Foundation
2626
/// Wrapper for IQKeyboardManager compatible types. This type provides an extension point for
2727
/// convenience methods in IQKeyboardManager.
2828
@available(iOSApplicationExtension, unavailable)
29-
public struct IQKeyboardManagerWrapper<Base> {
30-
public let base: Base
29+
public struct IQKeyboardManagerWrapper<Base: AnyObject> {
30+
public private(set) weak var base: Base?
3131
public init(_ base: Base) {
3232
self.base = base
3333
}
@@ -39,7 +39,7 @@ public struct IQKeyboardManagerWrapper<Base> {
3939
@available(iOSApplicationExtension, unavailable)
4040
public protocol IQKeyboardManagerCompatible {
4141
/// Type being extended.
42-
associatedtype Base
42+
associatedtype Base: AnyObject
4343

4444
/// Instance IQKeyboardManager extension point.
4545
@MainActor
@@ -48,7 +48,7 @@ public protocol IQKeyboardManagerCompatible {
4848

4949
// swiftlint:disable unused_setter_value
5050
@available(iOSApplicationExtension, unavailable)
51-
public extension IQKeyboardManagerCompatible {
51+
public extension IQKeyboardManagerCompatible where Self: AnyObject {
5252

5353
/// Instance IQKeyboardManager extension point.
5454
@MainActor

IQKeyboardManagerSwift/IQToolbar/IQUIView+IQKeyboardToolbar.swift

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,22 +41,24 @@ public extension IQKeyboardManagerWrapper where Base: UIView {
4141
IQToolbar references for better customization control.
4242
*/
4343
var toolbar: IQToolbar {
44-
var toolbar: IQToolbar? = base.inputAccessoryView as? IQToolbar
44+
var toolbar: IQToolbar? = base?.inputAccessoryView as? IQToolbar
4545

46-
if toolbar == nil {
46+
if toolbar == nil, let base = base {
4747
toolbar = objc_getAssociatedObject(base, &AssociatedKeys.toolbar) as? IQToolbar
4848
}
4949

5050
if let unwrappedToolbar: IQToolbar = toolbar {
5151
return unwrappedToolbar
5252
} else {
5353

54-
let width: CGFloat = base.window?.windowScene?.screen.bounds.width ?? 0
54+
let width: CGFloat = base?.window?.windowScene?.screen.bounds.width ?? 0
5555

5656
let frame = CGRect(origin: .zero, size: .init(width: width, height: 44))
5757
let newToolbar = IQToolbar(frame: frame)
5858

59-
objc_setAssociatedObject(base, &AssociatedKeys.toolbar, newToolbar, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
59+
if let base = base {
60+
objc_setAssociatedObject(base, &AssociatedKeys.toolbar, newToolbar, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
61+
}
6062

6163
return newToolbar
6264
}
@@ -69,12 +71,17 @@ public extension IQKeyboardManagerWrapper where Base: UIView {
6971
*/
7072
var hidePlaceholder: Bool {
7173
get {
72-
return objc_getAssociatedObject(base, &AssociatedKeys.hidePlaceholder) as? Bool ?? false
74+
if let base = base {
75+
return objc_getAssociatedObject(base, &AssociatedKeys.hidePlaceholder) as? Bool ?? false
76+
}
77+
return false
7378
}
7479
set(newValue) {
75-
objc_setAssociatedObject(base, &AssociatedKeys.hidePlaceholder,
76-
newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
77-
toolbar.titleBarButton.title = drawingPlaceholder
80+
if let base = base {
81+
objc_setAssociatedObject(base, &AssociatedKeys.hidePlaceholder,
82+
newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
83+
toolbar.titleBarButton.title = drawingPlaceholder
84+
}
7885
}
7986
}
8087

@@ -83,11 +90,16 @@ public extension IQKeyboardManagerWrapper where Base: UIView {
8390
*/
8491
var placeholder: String? {
8592
get {
86-
return objc_getAssociatedObject(base, &AssociatedKeys.placeholder) as? String
93+
if let base = base {
94+
return objc_getAssociatedObject(base, &AssociatedKeys.placeholder) as? String
95+
}
96+
return nil
8797
}
8898
set(newValue) {
89-
objc_setAssociatedObject(base, &AssociatedKeys.placeholder, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
90-
toolbar.titleBarButton.title = drawingPlaceholder
99+
if let base = base {
100+
objc_setAssociatedObject(base, &AssociatedKeys.placeholder, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
101+
toolbar.titleBarButton.title = drawingPlaceholder
102+
}
91103
}
92104
}
93105

@@ -128,7 +140,7 @@ public extension IQKeyboardManagerWrapper where Base: UIView {
128140
titleAccessibilityLabel: String? = nil) {
129141

130142
// If can't set InputAccessoryView. Then return
131-
if base.responds(to: #selector(setter: UITextField.inputAccessoryView)) {
143+
if base?.responds(to: #selector(setter: UITextField.inputAccessoryView)) == true {
132144

133145
// Creating a toolBar for phoneNumber keyboard
134146
let toolbar: IQToolbar = toolbar
@@ -200,14 +212,14 @@ public extension IQKeyboardManagerWrapper where Base: UIView {
200212
}
201213

202214
// Setting toolbar to keyboard.
203-
let reloadInputViews: Bool = base.inputAccessoryView != toolbar
215+
let reloadInputViews: Bool = base?.inputAccessoryView != toolbar
204216
if reloadInputViews {
205217
if let textField: UITextField = base as? UITextField {
206218
textField.inputAccessoryView = toolbar
207219
} else if let textView: UITextView = base as? UITextView {
208220
textView.inputAccessoryView = toolbar
209221
}
210-
base.reloadInputViews()
222+
base?.reloadInputViews()
211223
}
212224
}
213225
}

IQKeyboardManagerSwift/UIKitExtensions/IQUIScrollView+Additions.swift

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,16 @@ public extension IQKeyboardManagerWrapper where Base: UIScrollView {
5656
*/
5757
var ignoreScrollingAdjustment: Bool {
5858
get {
59-
return objc_getAssociatedObject(base, &AssociatedKeys.ignoreScrollingAdjustment) as? Bool ?? false
59+
if let base = base {
60+
return objc_getAssociatedObject(base, &AssociatedKeys.ignoreScrollingAdjustment) as? Bool ?? false
61+
}
62+
return false
6063
}
6164
set(newValue) {
62-
objc_setAssociatedObject(base, &AssociatedKeys.ignoreScrollingAdjustment,
63-
newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
65+
if let base = base {
66+
objc_setAssociatedObject(base, &AssociatedKeys.ignoreScrollingAdjustment,
67+
newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
68+
}
6469
}
6570
}
6671

@@ -70,11 +75,16 @@ public extension IQKeyboardManagerWrapper where Base: UIScrollView {
7075
*/
7176
var ignoreContentInsetAdjustment: Bool {
7277
get {
73-
return objc_getAssociatedObject(base, &AssociatedKeys.ignoreContentInsetAdjustment) as? Bool ?? false
78+
if let base = base {
79+
return objc_getAssociatedObject(base, &AssociatedKeys.ignoreContentInsetAdjustment) as? Bool ?? false
80+
}
81+
return false
7482
}
7583
set(newValue) {
76-
objc_setAssociatedObject(base, &AssociatedKeys.ignoreContentInsetAdjustment,
77-
newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
84+
if let base = base {
85+
objc_setAssociatedObject(base, &AssociatedKeys.ignoreContentInsetAdjustment,
86+
newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
87+
}
7888
}
7989
}
8090

@@ -83,11 +93,16 @@ public extension IQKeyboardManagerWrapper where Base: UIScrollView {
8393
*/
8494
var restoreContentOffset: Bool {
8595
get {
86-
return objc_getAssociatedObject(base, &AssociatedKeys.restoreContentOffset) as? Bool ?? false
96+
if let base = base {
97+
return objc_getAssociatedObject(base, &AssociatedKeys.restoreContentOffset) as? Bool ?? false
98+
}
99+
return false
87100
}
88101
set(newValue) {
89-
objc_setAssociatedObject(base, &AssociatedKeys.restoreContentOffset,
90-
newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
102+
if let base = base {
103+
objc_setAssociatedObject(base, &AssociatedKeys.restoreContentOffset,
104+
newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
105+
}
91106
}
92107
}
93108
}

IQKeyboardManagerSwift/UIKitExtensions/IQUITextFieldView+Additions.swift

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,18 @@ public extension IQKeyboardManagerWrapper where Base: UIView {
5454
*/
5555
var distanceFromKeyboard: CGFloat {
5656
get {
57-
if let value = objc_getAssociatedObject(base, &AssociatedKeys.distanceFromKeyboard) as? CGFloat {
58-
return value
59-
} else {
60-
return UIView.defaultKeyboardDistance
57+
if let base = base {
58+
if let value = objc_getAssociatedObject(base, &AssociatedKeys.distanceFromKeyboard) as? CGFloat {
59+
return value
60+
}
6161
}
62+
return UIView.defaultKeyboardDistance
6263
}
6364
set(newValue) {
64-
objc_setAssociatedObject(base, &AssociatedKeys.distanceFromKeyboard,
65-
newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
65+
if let base = base {
66+
objc_setAssociatedObject(base, &AssociatedKeys.distanceFromKeyboard,
67+
newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
68+
}
6669
}
6770
}
6871

@@ -73,11 +76,16 @@ public extension IQKeyboardManagerWrapper where Base: UIView {
7376
*/
7477
var ignoreSwitchingByNextPrevious: Bool {
7578
get {
76-
return objc_getAssociatedObject(base, &AssociatedKeys.ignoreSwitchingByNextPrevious) as? Bool ?? false
79+
if let base = base {
80+
return objc_getAssociatedObject(base, &AssociatedKeys.ignoreSwitchingByNextPrevious) as? Bool ?? false
81+
}
82+
return false
7783
}
7884
set(newValue) {
79-
objc_setAssociatedObject(base, &AssociatedKeys.ignoreSwitchingByNextPrevious,
80-
newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
85+
if let base = base {
86+
objc_setAssociatedObject(base, &AssociatedKeys.ignoreSwitchingByNextPrevious,
87+
newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
88+
}
8189
}
8290
}
8391

@@ -86,10 +94,15 @@ public extension IQKeyboardManagerWrapper where Base: UIView {
8694
*/
8795
var enableMode: IQEnableMode {
8896
get {
89-
return objc_getAssociatedObject(base, &AssociatedKeys.enableMode) as? IQEnableMode ?? .default
97+
if let base = base {
98+
return objc_getAssociatedObject(base, &AssociatedKeys.enableMode) as? IQEnableMode ?? .default
99+
}
100+
return .default
90101
}
91102
set(newValue) {
92-
objc_setAssociatedObject(base, &AssociatedKeys.enableMode, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
103+
if let base = base {
104+
objc_setAssociatedObject(base, &AssociatedKeys.enableMode, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
105+
}
93106
}
94107
}
95108

@@ -98,11 +111,16 @@ public extension IQKeyboardManagerWrapper where Base: UIView {
98111
*/
99112
var resignOnTouchOutsideMode: IQEnableMode {
100113
get {
101-
return objc_getAssociatedObject(base, &AssociatedKeys.resignOnTouchOutsideMode) as? IQEnableMode ?? .default
114+
if let base = base {
115+
return objc_getAssociatedObject(base, &AssociatedKeys.resignOnTouchOutsideMode) as? IQEnableMode ?? .default
116+
}
117+
return .default
102118
}
103119
set(newValue) {
104-
objc_setAssociatedObject(base, &AssociatedKeys.resignOnTouchOutsideMode,
105-
newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
120+
if let base = base {
121+
objc_setAssociatedObject(base, &AssociatedKeys.resignOnTouchOutsideMode,
122+
newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
123+
}
106124
}
107125
}
108126
}

0 commit comments

Comments
 (0)