deinitialize() was obsoleted in swift 5.0 - swift

I was using a pod for ftp picture upload issue. But it is giving an error after I build the app with Swift 5.0.
Here is the error:
deinitialize()' is unavailable: the default argument to deinitialize(count:) has been removed, please specify the count explicitly.
Here is the Swift file belongs to pod:
import Foundation
/* Resource type, values defined in `sys/dirent.h`. */
public enum ResourceType: String {
case Unknown = "Unknown" // DT_UNKNOWN
case Directory = "Directory" // DT_DIR
case RegularFile = "RegularFile" // DT_REG
case SymbolicLink = "SymbolicLink" // DT_LNK
case NamedPipe = "NamedPipe" // DT_FIFO
case CharacterDevice = "CharacterDevice" // DT_CHR
case BlockDevice = "BlockDevice" // DT_BLK
case LocalDomainSocket = "LocalDomainSocket" // DT_SOCK
case Whiteout = "Whiteout" // DT_WHT
}
open class ResourceItem: CustomStringConvertible {
open var type: ResourceType = .Unknown
open var name: String = ""
open var link: String = ""
open var date: Date = Date()
open var size: Int = 0
open var mode: Int = 0
open var owner: String = ""
open var group: String = ""
open var path: String = "/"
open var description: String {
get {
return "\nResourceItem: \(name), \(type.rawValue)"
}
}
}
private let _resourceTypeMap: [Int:ResourceType] = [
Int(DT_UNKNOWN): ResourceType.Unknown,
Int(DT_FIFO): ResourceType.NamedPipe,
Int(DT_SOCK): ResourceType.LocalDomainSocket,
Int(DT_CHR): ResourceType.CharacterDevice,
Int(DT_DIR): ResourceType.Directory,
Int(DT_BLK): ResourceType.BlockDevice,
Int(DT_REG): ResourceType.RegularFile,
Int(DT_LNK): ResourceType.SymbolicLink,
Int(DT_WHT): ResourceType.Whiteout
]
/** Operation for resource listing. */
internal class ResourceListOperation: ReadStreamOperation {
fileprivate var inputData: NSMutableData?
var resources: [ResourceItem]?
override func streamEventEnd(_ aStream: Stream) -> (Bool, NSError?) {
var offset = 0
let bytes = self.inputData!.bytes.bindMemory(to: UInt8.self, capacity: (self.inputData?.length)!)
let totalBytes = CFIndex(self.inputData!.length)
var parsedBytes = CFIndex(0)
let entity = UnsafeMutablePointer<Unmanaged<CFDictionary>?>.allocate(capacity: 1)
var resources = [ResourceItem]()
repeat {
parsedBytes = CFFTPCreateParsedResourceListing(nil, bytes.advanced(by: offset), totalBytes - offset, entity)
if parsedBytes > 0 {
let value = entity.pointee?.takeUnretainedValue()
if let fptResource = value {
resources.append(self.mapFTPResources(fptResource))
}
offset += parsedBytes
}
} while parsedBytes > 0
self.resources = resources
entity.deinitialize()
return (true, nil)
}
fileprivate func mapFTPResources(_ ftpResources: NSDictionary) -> ResourceItem {
let item = ResourceItem()
if let mode = ftpResources[kCFFTPResourceMode as String] as? Int {
item.mode = mode
}
if let name = ftpResources[kCFFTPResourceName as String] as? String {
// CFFTPCreateParsedResourceListing assumes that teh names are in MacRoman.
// To fix it we create data from string and read it with correct encoding.
// https://devforums.apple.com/message/155626#155626
if configuration.encoding == String.Encoding.macOSRoman {
item.name = name
} else if let nameData = name.data(using: String.Encoding.macOSRoman) {
if let encodedName = NSString(data: nameData, encoding: self.configuration.encoding.rawValue) {
item.name = encodedName as String
}
}
item.path = self.path! + item.name
}
if let owner = ftpResources[kCFFTPResourceOwner as String] as? String {
item.owner = owner
}
if let group = ftpResources[kCFFTPResourceGroup as String] as? String {
item.group = group
}
if let link = ftpResources[kCFFTPResourceLink as String] as? String {
item.link = link
}
if let size = ftpResources[kCFFTPResourceSize as String] as? Int {
item.size = size
}
if let type = ftpResources[kCFFTPResourceType as String] as? Int {
if let resourceType = _resourceTypeMap[type] {
item.type = resourceType
}
}
if let date = ftpResources[kCFFTPResourceModDate as String] as? Date {
item.date = date
}
return item
}
override func streamEventHasBytes(_ aStream: Stream) -> (Bool, NSError?) {
if let inputStream = aStream as? InputStream {
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: 1024)
let result = inputStream.read(buffer, maxLength: 1024)
if result > 0 {
if self.inputData == nil {
self.inputData = NSMutableData(bytes: buffer, length: result)
} else {
self.inputData!.append(buffer, length: result)
}
}
buffer.deinitialize()
}
return (true, nil)
}
}
Can you help me how can I fix these 2 below lines:
buffer.deinitialize()
entity.deinitialize()
And is it okay if we fix these two lines? I mean does the pod work after we fix these two lines?

deinitialize now requires a count parameter indicating how many values you want to deinitialise.
From the context, the code is probably trying to deinitialise everything the pointer references, so the number of values we deinitialise will be equal to the number of values we allocate. This will be 1024 for buffer and 1 for entity.
You should replace those lines with:
buffer.deinitialize(count: 1024)
// and
entity.deinitialize(count: 1)
respectively
However, since this is code from a pod that you are modifying, make sure to check the terms in the licence of the pod to make sure you are not violating anything.
You should also inform the author of the pod that the pod needs updating. This API change is made in Swift 4.1, I think, so it's quite old.

Related

protobuf based spring boot end point giving no output to swift client

I have a spring boot based micro-service endpoint which produces protobuf. Here is the .proto definition:
syntax = "proto3";
package TournamentFilterPackage;
import "google/protobuf/any.proto";
option java_package = "com.mycompany.service.tournament.proto";
option java_outer_classname = "TournamentCompleteData";
message TournamentData {
repeated TournamentRecord tournamentRecords = 1;
}
message TournamentRecord {
int64 id = 1;
Date start = 2;
float prize = 3;
string name = 4;
string speed = 5;
string type = 6;
float buyIn = 7;
int32 noOfParticipants = 8;
string status = 9;
}
message Date {
int32 year = 1;
int32 month = 2;
int32 day = 3;
}
message PokerResponseProto {
repeated int32 errorCodes = 1;
google.protobuf.Any responseObject = 2;
}
Here is my rest controller:
#ApiOperation(value="Complete Tournament Data", response = PokerResponseProto.class)
#GetMapping(value="/tournaments/completedata", produces = "application/x-protobuf")
public ResponseEntity<PokerResponseProto> getCompleteTournamentdata() {
if (logger.isInfoEnabled()) {
logger.info("BEGIN::/lobby/api/v1//tournaments/completedata/ " + "GET ::");
}
List<TournamentTypeResponseDto> tournamentTypeResponseDtos = new ArrayList<>();
List<TournamentRecord> tournamentRecords = new ArrayList<>();
ResponseEntity<PokerResponseProto> pokerResponse = null;
try {
tournamentTypeResponseDtos =
tournamentTypeDataService.getCompleteTournamentList();
for(TournamentTypeResponseDto t:tournamentTypeResponseDtos) {
tournamentRecords.add(controllerUtils.buildTournamentRecord(t));
}
TournamentData.Builder tournamentDataBuilder =
TournamentData.newBuilder().addAllTournamentRecords(tournamentRecords);
pokerResponse = new ResponseEntity<>(BKPokerResponseProto.newBuilder()
.setResponseObject(Any.pack(tournamentDataBuilder.build()))
.build(),
HttpStatus.OK);
logger.info("pokerResponse: {}", pokerResponse.toString());
} catch (PokerException pe) {
if (this.logger.isErrorEnabled()) {
this.logger.error(pe.getMessage(), bkpe);
}
List<Integer> errorCodeValue = controllerUtils
.convertErrorCodesToInt(bkpe.getErrorCodes());
pokerResponse = new ResponseEntity<>(PokerResponseProto.newBuilder()
.addAllErrorCodes(errorCodeValue)
.build(), HttpStatus.INTERNAL_SERVER_ERROR);
}
if (logger.isInfoEnabled()) {
logger.info("RETURN::/lobby/api/v1//tournaments/completedata/ " + "GET :: {}",
pokerResponse.toString());
}
return pokerResponse;
}
Here is the code snippet from ControllerUtils class:
public TournamentRecord buildTournamentRecord(TournamentTypeResponseDto dto) {
Instant tournamentStart = dto.getTournamentStartDate();
LocalDate localDate1 = LocalDateTime.ofInstant(tournamentStart,
ZoneOffset.UTC).toLocalDate();
Date.Builder dateBuilder1 = Date.newBuilder();
dateBuilder1.setYear(localDate1.getYear());
dateBuilder1.setMonth(localDate1.getMonthValue());
dateBuilder1.setDay(localDate1.getDayOfMonth());
TournamentCompleteData.Date trnamntStartDate = dateBuilder1.build();
TournamentRecord tr = TournamentRecord.newBuilder()
.setId(dto.getTournamentTypeId())
.setStart(trnamntStartDate)
.setPrize(dto.getFirstPrize())
.setName(dto.getTournamentName())
.setStatus(dto.getStatusName())
.build();
return tr;
}
I have written a test-case which can access this end-point & print the tournaments. But Swift client gets null when it invokes this end point. Already existing protobuf end points work fine with swift client & I have a ProtobufHttpMessageConverter already configured
#Bean
ProtobufHttpMessageConverter protobufHttpMessageConverter() {
return new ProtobufHttpMessageConverter();
}
And when the swift client invokes the end point, log messages get printed. That means client is invoking the end-point.
Here is the swift client code snippet for LobbyAPI:
import Foundation
class LobbyAPI: Api {
func getTournammentTableList(completion: #escaping ((TournamentFilterPackage_TournamentData?, Error?) -> Void)) {
getData(WithUrl: (APIConstants.lobbyURL) + "tournaments/completedata/", APIKey: APIConstants.apiKey, completion: completion)
}
For TournamentTableListVM
import Cocoa
import RealmSwift
class TournamentTableListVM: NSObject {
private weak var tblListView: LobbyTableListView!
private var tblPreviewVM: TablePreviewVM!
var arrFilterTableList: [LobbyFilterPackage_LobbyTableRecord] = []
var arrTableList: [LobbyFilterPackage_LobbyTableRecord] = []
var timer = Timer()
var didSelectTable: ((_ tableRecord: LobbyFilterPackage_LobbyTableRecord,_ isObserver:Bool) -> Void)!
var getFilterCallBack:(() -> Void)?
var currentSelectedMoneyType: (() -> TabMenuMoneyToggleView.Money) = { .play }{
didSet{
tblPreviewVM.currentSelectedMoneyType = currentSelectedMoneyType
}
}
var didTakeActionFromTablePreview: ((TablePreviewVM.TablePreviewPlayerActionType, Int) -> Void)?
//For sorting
var currentSortKey: String?
var currentSortAscending: Bool?
var aUserData: APPokerProto_PlayerProfileProto!
var observClick = false
func getCompleteTableData() {
LobbyAPI().getTournammentTableList() {[weak self] (aTournammentData, aError) in
guard let self = self else { return }
guard aError == nil, let tableData = aTournammentData, tableData.lobbyTableRecords.count > 0 else {
self.emptyTableAndPreview()
LoginManager.shared.didToggleNotify()
return
}
LoginManager.shared.didToggleNotify()
self.arrFilterTableList = tableData.lobbyTableRecords
self.arrTableList = tableData.lobbyTableRecords
self.tblListView.tblList.reloadData()
self.tblListView.tblList.selectRowIndexes(NSIndexSet.init(index: 0) as IndexSet, byExtendingSelection: true)
self.timeStamp = String(tableData.timeStamp.seconds)
}
}
In this above code "aTournammentData" is coming as nil.
Update Found that in front end swift, it was mapped to wrong generated swift struct. With the help of https://github.com/apple/swift-protobuf plugin TournamentCompleteData.pb.swift file was generated as below
// DO NOT EDIT.
// swift-format-ignore-file
//
// Generated by the Swift generator plugin for the protocol buffer compiler.
// Source: TournamentCompleteData.proto
//
// For information on using the generated types, please see the documentation:
// https://github.com/apple/swift-protobuf/
import Foundation
import SwiftProtobuf
// If the compiler emits an error on this type, it is because this file
// was generated by a version of the `protoc` Swift plug-in that is
// incompatible with the version of SwiftProtobuf to which you are linking.
// Please ensure that you are building against the same version of the API
// that was used to generate this file.
fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAPIVersionCheck {
struct _2: SwiftProtobuf.ProtobufAPIVersion_2 {}
typealias Version = _2
}
struct TournamentFilterPackage_TournamentData {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var tournamentRecords: [TournamentFilterPackage_TournamentRecord] = []
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
struct TournamentFilterPackage_TournamentRecord {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
var id: Int64 = 0
var start: TournamentFilterPackage_Date {
get {return _start ?? TournamentFilterPackage_Date()}
set {_start = newValue}
}
/// Returns true if `start` has been explicitly set.
var hasStart: Bool {return self._start != nil}
/// Clears the value of `start`. Subsequent reads from it will return its default value.
mutating func clearStart() {self._start = nil}
var prize: Float = 0
var name: String = String()
var speed: String = String()
var type: String = String()
var buyIn: Float = 0
var noOfParticipants: Int32 = 0
var status: String = String()
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _start: TournamentFilterPackage_Date? = nil
}
struct TournamentFilterPackage_Date {
// SwiftProtobuf.Message conformance is added in an extension below. See the
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
// methods supported on all messages.
/// Year of the date. Must be from 1 to 9999, or 0 to specify a date without
/// a year.
var year: Int32 = 0
/// Month of a year. Must be from 1 to 12, or 0 to specify a year without a
/// month and day.
var month: Int32 = 0
/// Day of a month. Must be from 1 to 31 and valid for the year and month, or 0
/// to specify a year by itself or a year and month where the day isn't
/// significant.
var day: Int32 = 0
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
}
// MARK: - Code below here is support for the SwiftProtobuf runtime.
fileprivate let _protobuf_package = "TournamentFilterPackage"
extension TournamentFilterPackage_TournamentData: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".TournamentData"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "tournamentRecords"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeRepeatedMessageField(value: &self.tournamentRecords) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if !self.tournamentRecords.isEmpty {
try visitor.visitRepeatedMessageField(value: self.tournamentRecords, fieldNumber: 1)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: TournamentFilterPackage_TournamentData, rhs: TournamentFilterPackage_TournamentData) -> Bool {
if lhs.tournamentRecords != rhs.tournamentRecords {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension TournamentFilterPackage_TournamentRecord: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".TournamentRecord"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "id"),
2: .same(proto: "start"),
3: .same(proto: "prize"),
4: .same(proto: "name"),
5: .same(proto: "speed"),
6: .same(proto: "type"),
7: .same(proto: "buyIn"),
8: .same(proto: "noOfParticipants"),
9: .same(proto: "status"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularInt64Field(value: &self.id) }()
case 2: try { try decoder.decodeSingularMessageField(value: &self._start) }()
case 3: try { try decoder.decodeSingularFloatField(value: &self.prize) }()
case 4: try { try decoder.decodeSingularStringField(value: &self.name) }()
case 5: try { try decoder.decodeSingularStringField(value: &self.speed) }()
case 6: try { try decoder.decodeSingularStringField(value: &self.type) }()
case 7: try { try decoder.decodeSingularFloatField(value: &self.buyIn) }()
case 8: try { try decoder.decodeSingularInt32Field(value: &self.noOfParticipants) }()
case 9: try { try decoder.decodeSingularStringField(value: &self.status) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
if self.id != 0 {
try visitor.visitSingularInt64Field(value: self.id, fieldNumber: 1)
}
try { if let v = self._start {
try visitor.visitSingularMessageField(value: v, fieldNumber: 2)
} }()
if self.prize != 0 {
try visitor.visitSingularFloatField(value: self.prize, fieldNumber: 3)
}
if !self.name.isEmpty {
try visitor.visitSingularStringField(value: self.name, fieldNumber: 4)
}
if !self.speed.isEmpty {
try visitor.visitSingularStringField(value: self.speed, fieldNumber: 5)
}
if !self.type.isEmpty {
try visitor.visitSingularStringField(value: self.type, fieldNumber: 6)
}
if self.buyIn != 0 {
try visitor.visitSingularFloatField(value: self.buyIn, fieldNumber: 7)
}
if self.noOfParticipants != 0 {
try visitor.visitSingularInt32Field(value: self.noOfParticipants, fieldNumber: 8)
}
if !self.status.isEmpty {
try visitor.visitSingularStringField(value: self.status, fieldNumber: 9)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: TournamentFilterPackage_TournamentRecord, rhs: TournamentFilterPackage_TournamentRecord) -> Bool {
if lhs.id != rhs.id {return false}
if lhs._start != rhs._start {return false}
if lhs.prize != rhs.prize {return false}
if lhs.name != rhs.name {return false}
if lhs.speed != rhs.speed {return false}
if lhs.type != rhs.type {return false}
if lhs.buyIn != rhs.buyIn {return false}
if lhs.noOfParticipants != rhs.noOfParticipants {return false}
if lhs.status != rhs.status {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}
extension TournamentFilterPackage_Date: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = _protobuf_package + ".Date"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
1: .same(proto: "year"),
2: .same(proto: "month"),
3: .same(proto: "day"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
while let fieldNumber = try decoder.nextFieldNumber() {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every case branch when no optimizations are
// enabled. https://github.com/apple/swift-protobuf/issues/1034
switch fieldNumber {
case 1: try { try decoder.decodeSingularInt32Field(value: &self.year) }()
case 2: try { try decoder.decodeSingularInt32Field(value: &self.month) }()
case 3: try { try decoder.decodeSingularInt32Field(value: &self.day) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
if self.year != 0 {
try visitor.visitSingularInt32Field(value: self.year, fieldNumber: 1)
}
if self.month != 0 {
try visitor.visitSingularInt32Field(value: self.month, fieldNumber: 2)
}
if self.day != 0 {
try visitor.visitSingularInt32Field(value: self.day, fieldNumber: 3)
}
try unknownFields.traverse(visitor: &visitor)
}
static func ==(lhs: TournamentFilterPackage_Date, rhs: TournamentFilterPackage_Date) -> Bool {
if lhs.year != rhs.year {return false}
if lhs.month != rhs.month {return false}
if lhs.day != rhs.day {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
}

How to remove duplicate characters from a string in Swift

ruby has the function string.squeeze, but I can't seem to find a swift equivalent.
For example I want to turn bookkeeper -> bokepr
Is my only option to create a set of the characters and then pull the characters from the set back to a string?
Is there a better way to do this?
Edit/update: Swift 4.2 or later
You can use a set to filter your duplicated characters:
let str = "bookkeeper"
var set = Set<Character>()
let squeezed = str.filter{ set.insert($0).inserted }
print(squeezed) // "bokepr"
Or as an extension on RangeReplaceableCollection which will also extend String and Substrings as well:
extension RangeReplaceableCollection where Element: Hashable {
var squeezed: Self {
var set = Set<Element>()
return filter{ set.insert($0).inserted }
}
}
let str = "bookkeeper"
print(str.squeezed) // "bokepr"
print(str[...].squeezed) // "bokepr"
I would use this piece of code from another answer of mine, which removes all duplicates of a sequence (keeping only the first occurrence of each), while maintaining order.
extension Sequence where Iterator.Element: Hashable {
func unique() -> [Iterator.Element] {
var alreadyAdded = Set<Iterator.Element>()
return self.filter { alreadyAdded.insert($0).inserted }
}
}
I would then wrap it with some logic which turns a String into a sequence (by getting its characters), unqiue's it, and then restores that result back into a string:
extension String {
func uniqueCharacters() -> String {
return String(self.characters.unique())
}
}
print("bookkeeper".uniqueCharacters()) // => "bokepr"
Here is a solution I found online, however I don't think it is optimal.
func removeDuplicateLetters(_ s: String) -> String {
if s.characters.count == 0 {
return ""
}
let aNum = Int("a".unicodeScalars.filter{$0.isASCII}.map{$0.value}.first!)
let characters = Array(s.lowercased().characters)
var counts = [Int](repeatElement(0, count: 26))
var visited = [Bool](repeatElement(false, count: 26))
var stack = [Character]()
var i = 0
for character in characters {
if let num = asciiValueOfCharacter(character) {
counts[num - aNum] += 1
}
}
for character in characters {
if let num = asciiValueOfCharacter(character) {
i = num - aNum
counts[i] -= 1
if visited[i] {
continue
}
while !stack.isEmpty, let peekNum = asciiValueOfCharacter(stack.last!), num < peekNum && counts[peekNum - aNum] != 0 {
visited[peekNum - aNum] = false
stack.removeLast()
}
stack.append(character)
visited[i] = true
}
}
return String(stack)
}
func asciiValueOfCharacter(_ character: Character) -> Int? {
let value = String(character).unicodeScalars.filter{$0.isASCII}.first?.value ?? 0
return Int(value)
}
Here is one way to do this using reduce(),
let newChar = str.characters.reduce("") { partial, char in
guard let _ = partial.range(of: String(char)) else {
return partial.appending(String(char))
}
return partial
}
As suggested by Leo, here is a bit shorter version of the same approach,
let newChar = str.characters.reduce("") { $0.range(of: String($1)) == nil ? $0.appending(String($1)) : $0 }
Just Another solution
let str = "Bookeeper"
let newChar = str.reduce("" , {
if $0.contains($1) {
return "\($0)"
} else {
return "\($0)\($1)"
}
})
print(str.replacingOccurrences(of: " ", with: ""))
Use filter and contains to remove duplicate values
let str = "bookkeeper"
let result = str.filter{!result.contains($0)}
print(result) //bokepr

string replace substring without NSString API

I would like to be able to find and replace occurrences of a substring in a native Swift string without bridging to the NS class. How can I accomplish this?
This is not a duplicate of this question, as that question is about replacing a single character. This question is about finding and replacing a substring, which may contain many characters.
Method without Foundation:
extension String {
func replacing(_ oldString: String, with newString: String) -> String {
guard !oldString.isEmpty, !newString.isEmpty else { return self }
let charArray = Array(self.characters)
let oldCharArray = Array(oldString.characters)
let newCharArray = Array(newString.characters)
var matchedChars = 0
var resultCharArray = [Character]()
for char in charArray {
if char == oldCharArray[matchedChars] {
matchedChars += 1
if matchedChars == oldCharArray.count {
resultCharArray.append(contentsOf: newCharArray)
matchedChars = 0
}
} else {
for i in 0 ..< matchedChars {
resultCharArray.append(oldCharArray[i])
}
if char == oldCharArray[0] {
matchedChars = 1
} else {
matchedChars = 0
resultCharArray.append(char)
}
}
}
return String(resultCharArray)
}
}
Example usage:
let myString = "Hello World HelHelloello Hello HellHellooo"
print(myString.replacing("Hello", with: "Hi"))
Output:
Hi World HelHiello Hi HellHioo
Method using Foundation:
You can use the replacingOccurrences method on the String struct.
let myString = "Hello World"
let newString = myString.replacingOccurrences(of: "World", with: "Everyone")
print(newString) // prints "Hello Everyone"
generic and pure Swift approach
func splitBy<T: RangeReplaceableCollection>(_ s:T, by:T)->[T] where T.Iterator.Element:Equatable {
var tmp = T()
var res = [T]()
var i:T.IndexDistance = 0
let count = by.count
var pc:T.Iterator.Element {
get {
i %= count
let idx = by.index(by.startIndex, offsetBy: i)
return by[idx]
}
}
for sc in s {
if sc != pc {
i = 0
if sc != pc {
} else {
i = i.advanced(by: 1)
}
} else {
i = i.advanced(by: 1)
}
tmp.append(sc)
if i == count {
tmp.removeSubrange(tmp.index(tmp.endIndex, offsetBy: -i)..<tmp.endIndex)
res.append(tmp)
tmp.removeAll()
}
}
res.append(tmp)
return res
}
func split(_ s:String, by:String)->[String] {
return splitBy(s.characters, by: by.characters).map(String.init)
}
extension RangeReplaceableCollection where Self.Iterator.Element: Equatable {
func split(by : Self)->[Self] {
return splitBy(self, by: by)
}
}
how to use it?
let str = "simple text where i would like to replace something with anything"
let pat = "something"
let rep = "anything"
let s0 = str.characters.split(by: pat.characters).map(String.init)
let res = s0.joined(separator: rep)
print(res) // simple text where i would like to replace anything with anything
let res2 = split(str, by: pat).joined(separator: rep)
print(res2) // simple text where i would like to replace anything with anything
let arr = [1,2,3,4,1,2,3,4,1,2,3]
let p = [4,1]
print(arr.split(by: p)) // [[1, 2, 3], [2, 3], [2, 3]]

Realm/Swift: compilation error: Missing argument for parameter 'forPrimaryKey' in call

I'm trying to get my head around swift & realm, so I've created some kind of a test pad programme.
My model is defined like so
class RealmRecord: Object {
// properties
dynamic var id: Int = 0;
dynamic var text: String = ""
dynamic var var1: Double = 0.0
dynamic var var2: Int = 0
dynamic var var3: Double = 0.0
dynamic var var4: Int = 0
dynamic var cdate: Date = Date()
dynamic var cusr: String = ""
dynamic var mdate: Date = Date.distantPast
dynamic var musr: String = ""
dynamic var mcnt: Int = 0
// methods
convenience init(id: Int? = 0, text: String? = "", var1: Double? = 0.0,
var2: Int? = 0, var3: Double? = 0.0, var4: Int? = 0,
cusr: String? = "") {
self.init()
self.id = id!
self.text = text!
self.var1 = var1!
self.var2 = var2!
self.var3 = var3!
self.var4 = var4!
self.cdate = Date()
self.cusr = cusr!
self.mdate = Date.distantPast
self.musr = ""
self.mcnt = 0
} // init
override static func primaryKey() -> String? {
return "id"
} // primaryKey
} // RealmRecord
Persisting the data is accomplished by
try recRealm?.write {
recRealm?.add(self.rec, update: true)
} // try
But when adding the data retrieval via
if let inrec = self.recRealm?.object(RealmRecord.self) {
return inrec
} else {
return List<RealmRecord>()
} // if/else
I'm receiving an error message while compiling the code, reading
DataRealmRecord.swift:84:39: Missing argument for parameter 'forPrimaryKey' in call
Looking at the Realm documentation reveals only retrieving all persisted data--apparently without having a primary key defined--, or, alternatively, a single object, specified by the primary key.
Sifting through The Net brings up pretty much the same.
Given the model above, how can I retrieve all persisted data?
-- Sil68
EDIT
I've also defined a class facilitating this Realm model of mine, which basically carries out the following steps:
generate some random data;
persist data via the Realm model;
read data in again;
compare generated with read data.
The code
import Foundation
import RealmSwift
class DataRealmRecord {
// properties
private(set) var recDBPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
private(set) var recDBSubPath = "Persistency"
private(set) var recDBFile = "data.realm"
private(set) var recRealm: Realm?
private(set) var recRealmCfg: Realm.Configuration?
private(set) var rec = List<RealmRecord>()
private(set) var startTime = 0.0
private(set) var stopTime = 0.0
private(set) var runTime = 0.0
private(set) var outLog = ""
private(set) var realmOk = false
// methods
init() {
// assemble destination folder/database name
do {
try FileManager.default.createDirectory(atPath: recDBPath + "/" +
recDBSubPath,
withIntermediateDirectories: true,
attributes: nil)
recDBFile = recDBPath + "/" + recDBSubPath + "/" + recDBFile
realmOk = true
} catch let error as NSError {
outLog += error.localizedDescription
realmOk = false
} // do/try/catch
// configure realm database
if (realmOk) {
self.recRealmCfg = Realm.Configuration(fileURL: Foundation.URL(string: self.recDBFile))
do {
self.recRealm = try Realm(configuration: self.recRealmCfg!)
realmOk = true
} catch let error as NSError {
outLog += error.localizedDescription
realmOk = false
} // do/try/catch
} // if
} // init
// generate test data
func generateData(noRecs: Int? = 1000, simDat: SimulateData?) {
for i in 1...noRecs! {
let realmRec = RealmRecord(id: i,
text: String(format: "Record #%04d", i),
var1: simDat?.datnorm[i - 1] ?? 1.1,
var2: simDat?.datpois[i - 1] ?? 2,
var3: simDat?.datunif[i - 1] ?? 3.3,
var4: simDat?.datbern[i - 1] ?? 4,
cusr: "me")
self.rec.append(realmRec)
} // for
} // generateData
// retrieve test data from persistent storage
func loadData() -> List<RealmRecord> {
if let inrec = self.recRealm?.object(RealmRecord.self) {
return inrec
} else {
return List<RealmRecord>()
} // if/else
} // loadData
// save test data to persistent storage
func saveData() {
do {
try recRealm?.write {
recRealm?.add(self.rec, update: true)
} // try
} catch let error as NSError {
outLog += error.localizedDescription
} // do/try/catch
} // saveData
// compare two data sets
func compareData(rec1: List<RealmRecord>, rec2: List<RealmRecord>) -> Bool {
var rc = false
if rec1.count == rec2.count {
rc = true
for i in 0..<rec1.count {
rc = rc && (rec1[i] == rec2[i])
} // for
} // if
return rc
} // compareData
// run a full evaluation cycle
// (1) generate test data;
// (2) save test data to persistant storage;
// (3) retrieve test data from persistant storage;
// (4) compare generated data with retrieved data.
func fullCycle(noRecs: Int? = 1000, simDat: SimulateData?, prnData: Bool? = false) {
// start execution time measurement
self.startTime = Double(CFAbsoluteTimeGetCurrent())
// execute the full cycle
self.generateData(noRecs: noRecs, simDat: simDat) // (1)
self.saveData() // (2)
let rec2 = self.loadData() // (3)
let cmpRec = compareData(rec1: self.rec, rec2: rec2) // (4)
// stop execution time measurement & calculate elapsed time
self.stopTime = Double(CFAbsoluteTimeGetCurrent())
self.runTime = self.stopTime - self.startTime
} // fullCycle
} // DataRealmRecord
Issue at hand is, this code fails to compile due to the error message mentioned above (in method loadData()).
The Swift compiler is telling you that it thinks you're trying to call Realm.object(ofType:forPrimaryKey:), which retrieves a single object based on the value of its primary key. It sounds like you really want to call Realm.objects(_:) to retrieve all objects of a given type. Note that this returns a Results<T>, not a List<T>.

OS X API to enumerate a folder including AppleDouble files (beginning with a "._")?

The following 4 NSFileManager API fail to enumerate AppleDouble files beginning with a "._"
enumeratorAtPath,
enumeratorAtURL,
contentsOfDirectoryAtPath,
contentsOfDirectoryAtURL
Which API should be used to get them enumerated without fail?
The below does the job, just in case someone needs it
func contentsOfDirectoryUsingCAPI() -> [String]? {
var contentsOfDirectory: [String]?
if let folderPathCString = fileURL.path!.cStringUsingEncoding(NSUTF8StringEncoding) {
// Open the directory
let dir = opendir(folderPathCString)
if dir != nil {
contentsOfDirectory = []
// Use readdir to get each element
var entry = readdir(dir)
while entry != nil {
let d_namlen = entry.memory.d_namlen
let d_name = entry.memory.d_name
// dirent.d_name is defined as a tuple with
// MAXNAMLEN elements. We want to convert
// that to a null-terminated C string.
var nameBuf: [CChar] = Array()
let mirror = Mirror(reflecting: d_name)
for _ in 0..<d_namlen {
for child in mirror.children {
if let value = child.value as? CChar {
nameBuf.append(value)
}
}
}
// Null-terminate it and convert to a String
nameBuf.append(0)
if let name = String.fromCString(nameBuf) {
contentsOfDirectory?.append(name)
}
entry = readdir(dir)
}
closedir(dir)
}
}
return contentsOfDirectory
}