Skip to content
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

Fix SwiftLint Errors #9

Closed
wants to merge 29 commits into from
Closed
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e0e4130
Fix Swift Lint Errors
ShawnBaek Dec 30, 2018
12e1ac7
Set Travis target to xcode10
ShawnBaek Dec 30, 2018
a723b27
Rollback podspec
ShawnBaek Dec 30, 2018
710d707
Add @discardableResult
ShawnBaek Dec 30, 2018
600fa81
Fix Test Cases
ShawnBaek Dec 30, 2018
d774249
Acted on Reviers comment
ShawnBaek Dec 30, 2018
e527903
Add subscript function for [Any] to fix ParseSwiftTests cases
ShawnBaek Dec 31, 2018
05a86e7
Update Podspec
ShawnBaek Dec 31, 2018
378248c
Revert for @discardableResult
ShawnBaek Jan 1, 2019
7399d37
Acted on @mooshee feedback
ShawnBaek Jan 1, 2019
f866536
remove discardableResult for removeAllObjects
ShawnBaek Jan 1, 2019
15c1d9a
Update Pod Script : pod lib lint --verbose --no-clean
ShawnBaek Jan 2, 2019
e6aeec0
Revert KeychainStore.swift
ShawnBaek Jan 2, 2019
f487baf
Revert travis.yml
ShawnBaek Jan 2, 2019
868ec78
Adds more verbose logs for pod lib lint
flovilmart Jan 5, 2019
f2e18e3
Add Codable Structure to set and get complexObject.
ShawnBaek Jan 6, 2019
dca1bc2
Merge branch 'upstream-master' of github.com:ShawnBaek/Parse-Swift in…
ShawnBaek Jan 6, 2019
fed6eb7
declare ComplexObject Struct in Class
ShawnBaek Jan 6, 2019
e776abb
set IPHONE_DEPLOYMENT_TARGET = 10.0
ShawnBaek Jan 6, 2019
fe0d859
Add test spec in PodSpec
ShawnBaek Jan 6, 2019
47c0932
Revert podspec, print cocoapods version
flovilmart Jan 6, 2019
3b81390
Use cocoapods > 1.6.0 in order to workaround lint issue
flovilmart Jan 6, 2019
3ba6ee4
Revert "set IPHONE_DEPLOYMENT_TARGET = 10.0"
flovilmart Jan 6, 2019
9eb914e
lower pod iOS deployment target
flovilmart Jan 6, 2019
5927703
Revert
ShawnBaek Jan 7, 2019
5899b5a
Merge branch 'upstream-master' of github.com:ShawnBaek/Parse-Swift in…
ShawnBaek Jan 7, 2019
1eee004
revert testSetComplexObject
ShawnBaek Jan 7, 2019
5310345
Add AnyCodable
ShawnBaek Feb 16, 2019
18aae3e
Apply AnyCodable
ShawnBaek Feb 16, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
osx_image: xcode9
osx_image: xcode10
language: objective-c
stage: Build
env:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,7 @@ do {
acl?.publicWrite = true
loggedIn.ACL = acl
try loggedIn.save()
} catch let e {
e
e.localizedDescription
} catch let error {
fatalError("\(e.localizedDescription)")
ShawnBaek marked this conversation as resolved.
Show resolved Hide resolved
}

Expand Down
5 changes: 3 additions & 2 deletions ParseSwift.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ Pod::Spec.new do |s|
:git => "#{s.homepage}.git",
:tag => "#{s.version}",
}
s.ios.deployment_target = "8.0"
s.pod_target_xcconfig = { 'SWIFT_VERSION' => '4.0' }
ShawnBaek marked this conversation as resolved.
Show resolved Hide resolved
s.ios.deployment_target = "10.0"
s.osx.deployment_target = "10.10"
s.tvos.deployment_target = "9.0"
s.source_files = "Sources/ParseSwift/**/*.swift"
Expand All @@ -23,4 +24,4 @@ Pod::Spec.new do |s|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
LICENSE
}
end
end
27 changes: 16 additions & 11 deletions ParseSwift.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -435,11 +435,12 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0900;
LastUpgradeCheck = 0900;
LastUpgradeCheck = 1010;
ORGANIZATIONNAME = Parse;
TargetAttributes = {
4AA807571F794242008CD551 = {
CreatedOnToolsVersion = 9.0;
LastSwiftMigration = 1010;
ProvisioningStyle = Automatic;
};
4AB8B4F31F254AE10070F682 = {
Expand Down Expand Up @@ -673,7 +674,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.parse.TestHost;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
Expand All @@ -687,7 +688,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.parse.TestHost;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
Expand All @@ -706,13 +707,15 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
Expand Down Expand Up @@ -747,7 +750,7 @@
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 4.2;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
Expand All @@ -767,13 +770,15 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
Expand All @@ -800,7 +805,7 @@
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 4.2;
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
Expand All @@ -823,7 +828,7 @@
PRODUCT_NAME = ParseSwift;
SKIP_INSTALL = YES;
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
Expand All @@ -844,7 +849,7 @@
PRODUCT_NAME = ParseSwift;
SKIP_INSTALL = YES;
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
Expand All @@ -857,7 +862,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwiftTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestHost.app/TestHost";
};
Expand All @@ -871,7 +876,7 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwiftTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 4.2;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestHost.app/TestHost";
};
Expand All @@ -896,7 +901,7 @@
SDKROOT = macosx;
SKIP_INSTALL = YES;
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 4.2;
};
name = Debug;
};
Expand All @@ -919,7 +924,7 @@
SDKROOT = macosx;
SKIP_INSTALL = YES;
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
SWIFT_VERSION = 4.2;
};
name = Release;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0900"
LastUpgradeVersion = "1010"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand All @@ -26,9 +26,8 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES"
codeCoverageEnabled = "YES">
codeCoverageEnabled = "YES"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
Expand Down Expand Up @@ -57,7 +56,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0900"
LastUpgradeVersion = "1010"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand All @@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
Expand All @@ -37,7 +36,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
Expand Down
4 changes: 2 additions & 2 deletions Sources/ParseSwift/API/API+Commands.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,15 @@ extension API.Command where T: ObjectType {
}

static func batch(commands: [API.Command<T, T>]) -> RESTBatchCommandType<T> {
let commands = commands.flatMap { (command) -> API.Command<T, T>? in
let commands = commands.compactMap { (command) -> API.Command<T, T>? in
let path = ParseConfiguration.mountPath + command.path.urlComponent
guard let body = command.body else {
return nil
}
return API.Command<T, T>(method: command.method, path: .any(path),
body: body, mapper: command.mapper)
}
let bodies = commands.flatMap { (command) -> T? in
let bodies = commands.compactMap { (command) -> T? in
return command.body
}
let mapper = { (data: Data) -> [(T, ParseError?)] in
Expand Down
4 changes: 2 additions & 2 deletions Sources/ParseSwift/Asynchronous.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ private func runAsync<T>(options: API.Options,
queue.async {
do {
callback(try function(options), nil)
} catch let e {
callback(nil, e)
} catch let error {
callback(nil, error)
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions Sources/ParseSwift/Objects Protocols/ObjectType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ internal extension ObjectType {
extension ObjectType {
// Parse ClassName inference
public static var className: String {
let t = "\(type(of: self))"
return t.components(separatedBy: ".").first! // strip .Type
let classType = "\(type(of: self))"
return classType.components(separatedBy: ".").first! // strip .Type
}
public var className: String {
return Self.className
Expand Down Expand Up @@ -115,7 +115,7 @@ let dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .custom({ (dec) ->
let container = try dec.singleValueContainer()
let decodedString = try container.decode(String.self)
return dateFormatter.date(from: decodedString)!
} catch let e {
} catch let error {
let container = try dec.container(keyedBy: DateEncodingKeys.self)
if let decoded = try container.decodeIfPresent(String.self, forKey: .iso) {
return dateFormatter.date(from: decoded)!
Expand Down
52 changes: 44 additions & 8 deletions Sources/ParseSwift/Storage/KeychainStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Foundation

func getKeychainQueryTemplate(forService service: String) -> [String: String] {
var query = [String: String]()
if service.characters.count > 0 {
if service.count > 0 {
query[kSecAttrService as String] = service
}
query[kSecClass as String] = kSecClassGenericPassword as String
Expand All @@ -25,7 +25,7 @@ struct KeychainStore: SecureStorage {
synchronizationQueue = DispatchQueue(label: "com.parse.keychain.\(service)",
qos: .default,
attributes: .concurrent,
autoreleaseFrequency:.inherit,
autoreleaseFrequency: .inherit,
target: nil)
keychainQueryTemplate = getKeychainQueryTemplate(forService: service)
}
Expand All @@ -35,7 +35,6 @@ struct KeychainStore: SecureStorage {
query[kSecAttrAccount as String] = key
return query
}

func object<T>(forKey key: String) -> T? where T: Decodable {
guard let data = synchronizationQueue.sync(execute: { () -> Data? in
return self.data(forKey: key)
Expand All @@ -45,7 +44,16 @@ struct KeychainStore: SecureStorage {
return NSKeyedUnarchiver.unarchiveObject(with: data) as? T
}

func set<T>(object: T?, forKey key: String) -> Bool where T: Encodable {
func object<T>(forKey key: String) -> [T]? {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why adding this implementation?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added one subscript and two functions to set and get an [Any] to subscript in KeychainStore for pass testSetComplextObject Test Cases. But I would love to get your feedback. Thank you

subscript<T>(key: String) -> [T]? 
func object<T>(forKey key: String) -> [T]?
func set<T>(object: [T]?, forKey key: String) -> Bool

Copy link
Contributor

Choose a reason for hiding this comment

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

There should be no need for that, as a T can be an [U] if you specify it so.

Copy link
Contributor Author

@ShawnBaek ShawnBaek Jan 2, 2019

Choose a reason for hiding this comment

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

Thank you for advice me. I removed these implement.

I got an error message below

testStore["complexObject"] = complexObject //Cannot assign value of type '[Any]' to type '_?'
guard let retrievedObject: [Any] = testStore["complexObject"] else {
    return XCTFail("Should retrieve the object")
} //Value of optional type 'KeychainStore?' must be unwrapped to refer to member 'subscript' of wrapped base type 'KeychainStore'

So I removed where T: Decodable where T: Codable where T: Encodable
Is it ok? It works fine..

func object<T>(forKey key: String) -> T? {
        guard let data = synchronizationQueue.sync(execute: { () -> Data? in
            return self.data(forKey: key)
        }) else {
            return nil
        }
        if T.self is Decodable {
            return NSKeyedUnarchiver.unarchiveObject(with: data) as? T
        }
        else {
            return nil
        }
    }


func set<T>(object: T?, forKey key: String) -> Bool {
        guard let object = object, object is Encodable else {
            return removeObject(forKey: key)
        }
        let data = NSKeyedArchiver.archivedData(withRootObject: object)
        let query = keychainQuery(forKey: key)
        let update = [
            kSecValueData as String: data
        ]

        let status = synchronizationQueue.sync(flags: .barrier) { () -> OSStatus in
            if self.data(forKey: key) != nil {
                return SecItemUpdate(query as CFDictionary, update as CFDictionary)
            }
            let mergedQuery = query.merging(update) { (_, otherValue) -> Any in otherValue }
            return SecItemAdd(mergedQuery as CFDictionary, nil)
        }

        return status == errSecSuccess
    }


subscript<T>(key: String) -> T? {
        get {
            return object(forKey: key)
        }
        set (object) {
            _ = set(object: object, forKey: key)
        }
    }

Copy link
Contributor

Choose a reason for hiding this comment

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

So I removed where T: Decodable where T: Codable where T: Encodable
Is it ok? It works fine..

It is not OK, as we do not want at compile time to store non Codable entries.

Do we really need array support?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we don't need [Any] object support.

guard let data = synchronizationQueue.sync(execute: { () -> Data? in
return self.data(forKey: key)
}) else {
return nil
}
return NSKeyedUnarchiver.unarchiveObject(with: data) as? [T]
}

@discardableResult func set<T>(object: T?, forKey key: String) -> Bool where T: Encodable {
guard let object = object else {
return removeObject(forKey: key)
}
Expand All @@ -66,12 +74,40 @@ struct KeychainStore: SecureStorage {
return status == errSecSuccess
}

@discardableResult func set<T>(object: [T]?, forKey key: String) -> Bool {
guard let object = object else {
return removeObject(forKey: key)
}
let data = NSKeyedArchiver.archivedData(withRootObject: object)
let query = keychainQuery(forKey: key)
let update = [
kSecValueData as String: data
]
let status = synchronizationQueue.sync(flags: .barrier) { () -> OSStatus in
if self.data(forKey: key) != nil {
return SecItemUpdate(query as CFDictionary, update as CFDictionary)
}
let mergedQuery = query.merging(update) { (_, otherValue) -> Any in otherValue }
return SecItemAdd(mergedQuery as CFDictionary, nil)
}
return status == errSecSuccess
}

subscript<T>(key: String) -> T? where T: Codable {
get {
return object(forKey: key)
}
set (object) {
_ = set(object: object, forKey: key)
set(object: object, forKey: key)
}
}

subscript<T>(key: String) -> [T]? {
get {
return object(forKey: key)
}
set (object) {
set(object: object, forKey: key)
}
}

Expand All @@ -81,7 +117,7 @@ struct KeychainStore: SecureStorage {
}
}

func removeAllObjects() -> Bool {
@discardableResult func removeAllObjects() -> Bool {
ShawnBaek marked this conversation as resolved.
Show resolved Hide resolved
var query = keychainQueryTemplate as [String: Any]
query[kSecReturnAttributes as String] = kCFBooleanTrue
query[kSecMatchLimit as String] = kSecMatchLimitAll
Expand Down Expand Up @@ -140,7 +176,7 @@ extension KeychainStore /* TypedSubscript */ {
return object(forKey: key)
}
set (object) {
_ = set(object: object, forKey: key)
set(object: object, forKey: key)
}
}

Expand All @@ -149,7 +185,7 @@ extension KeychainStore /* TypedSubscript */ {
return object(forKey: key)
}
set (object) {
_ = set(object: object, forKey: key)
set(object: object, forKey: key)
}
}
}
4 changes: 2 additions & 2 deletions Sources/ParseSwift/Storage/SecureStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import Foundation

protocol SecureStorage {
init(service: String)
func object<T>(forKey: String) -> T? where T: Decodable
func set<T>(object: T?, forKey: String) -> Bool where T: Encodable
func object<T>(forKey key: String) -> T? where T: Decodable
@discardableResult func set<T>(object: T?, forKey: String) -> Bool where T: Encodable
ShawnBaek marked this conversation as resolved.
Show resolved Hide resolved

subscript <T>(key: String) -> T? where T: Codable { get }
func removeObject(forKey: String) -> Bool
Expand Down
Loading