Remove use of forEach.
This commit is contained in:
parent
c1c4c8b1b6
commit
ba0a2d3521
@ -491,7 +491,8 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
|||||||
} else {
|
} else {
|
||||||
if let title = item.titleFromAttributes, let folder = ensureFolder(with: title) {
|
if let title = item.titleFromAttributes, let folder = ensureFolder(with: title) {
|
||||||
folder.externalID = item.attributes?["nnw_externalID"] as? String
|
folder.externalID = item.attributes?["nnw_externalID"] as? String
|
||||||
item.items?.forEach { itemChild in
|
if let items = item.items {
|
||||||
|
for itemChild in items {
|
||||||
if let feedSpecifier = itemChild.feedSpecifier {
|
if let feedSpecifier = itemChild.feedSpecifier {
|
||||||
folder.addFeed(newFeed(with: feedSpecifier))
|
folder.addFeed(newFeed(with: feedSpecifier))
|
||||||
}
|
}
|
||||||
@ -500,6 +501,7 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func loadOPMLItems(_ items: [OPMLItem]) {
|
func loadOPMLItems(_ items: [OPMLItem]) {
|
||||||
addOPMLItems(OPMLNormalizer.normalize(items))
|
addOPMLItems(OPMLNormalizer.normalize(items))
|
||||||
@ -521,11 +523,13 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
|||||||
if topLevelFeeds.contains(feed) {
|
if topLevelFeeds.contains(feed) {
|
||||||
containers.append(self)
|
containers.append(self)
|
||||||
}
|
}
|
||||||
folders?.forEach { folder in
|
if let folders {
|
||||||
|
for folder in folders {
|
||||||
if folder.topLevelFeeds.contains(feed) {
|
if folder.topLevelFeeds.contains(feed) {
|
||||||
containers.append(folder)
|
containers.append(folder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return containers
|
return containers
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -925,7 +929,9 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
|||||||
|
|
||||||
public func debugDropConditionalGetInfo() {
|
public func debugDropConditionalGetInfo() {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
flattenedFeeds().forEach{ $0.dropConditionalGetInfo() }
|
for feed in flattenedFeeds() {
|
||||||
|
feed.dropConditionalGetInfo()
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1169,7 +1175,7 @@ private extension Account {
|
|||||||
for article in articles where !article.status.read {
|
for article in articles where !article.status.read {
|
||||||
unreadCountStorage[article.feedID, default: 0] += 1
|
unreadCountStorage[article.feedID, default: 0] += 1
|
||||||
}
|
}
|
||||||
feeds.forEach { (feed) in
|
for feed in feeds {
|
||||||
let unreadCount = unreadCountStorage[feed.feedID, default: 0]
|
let unreadCount = unreadCountStorage[feed.feedID, default: 0]
|
||||||
feed.unreadCount = unreadCount
|
feed.unreadCount = unreadCount
|
||||||
}
|
}
|
||||||
@ -1220,7 +1226,7 @@ private extension Account {
|
|||||||
var idDictionary = [String: Feed]()
|
var idDictionary = [String: Feed]()
|
||||||
var externalIDDictionary = [String: Feed]()
|
var externalIDDictionary = [String: Feed]()
|
||||||
|
|
||||||
flattenedFeeds().forEach { (feed) in
|
for feed in flattenedFeeds() {
|
||||||
idDictionary[feed.feedID] = feed
|
idDictionary[feed.feedID] = feed
|
||||||
if let externalID = feed.externalID {
|
if let externalID = feed.externalID {
|
||||||
externalIDDictionary[externalID] = feed
|
externalIDDictionary[externalID] = feed
|
||||||
|
@ -215,23 +215,31 @@ public final class AccountManager: UnreadCountProvider {
|
|||||||
|
|
||||||
public func suspendNetworkAll() {
|
public func suspendNetworkAll() {
|
||||||
isSuspended = true
|
isSuspended = true
|
||||||
accounts.forEach { $0.suspendNetwork() }
|
for account in accounts {
|
||||||
|
account.suspendNetwork()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func suspendDatabaseAll() {
|
public func suspendDatabaseAll() {
|
||||||
accounts.forEach { $0.suspendDatabase() }
|
for account in accounts {
|
||||||
|
account.suspendDatabase()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func resumeAll() {
|
public func resumeAll() {
|
||||||
isSuspended = false
|
isSuspended = false
|
||||||
accounts.forEach { $0.resumeDatabaseAndDelegate() }
|
for account in accounts {
|
||||||
accounts.forEach { $0.resume() }
|
account.resumeDatabaseAndDelegate()
|
||||||
|
}
|
||||||
|
for account in accounts {
|
||||||
|
account.resume()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func receiveRemoteNotification(userInfo: [AnyHashable : Any], completion: (() -> Void)? = nil) {
|
public func receiveRemoteNotification(userInfo: [AnyHashable : Any], completion: (() -> Void)? = nil) {
|
||||||
let group = DispatchGroup()
|
let group = DispatchGroup()
|
||||||
|
|
||||||
activeAccounts.forEach { account in
|
for account in activeAccounts {
|
||||||
group.enter()
|
group.enter()
|
||||||
account.receiveRemoteNotification(userInfo: userInfo) {
|
account.receiveRemoteNotification(userInfo: userInfo) {
|
||||||
group.leave()
|
group.leave()
|
||||||
@ -248,7 +256,7 @@ public final class AccountManager: UnreadCountProvider {
|
|||||||
|
|
||||||
let group = DispatchGroup()
|
let group = DispatchGroup()
|
||||||
|
|
||||||
activeAccounts.forEach { account in
|
for account in activeAccounts {
|
||||||
group.enter()
|
group.enter()
|
||||||
account.refreshAll() { result in
|
account.refreshAll() { result in
|
||||||
group.leave()
|
group.leave()
|
||||||
@ -272,7 +280,7 @@ public final class AccountManager: UnreadCountProvider {
|
|||||||
var syncErrors = [AccountSyncError]()
|
var syncErrors = [AccountSyncError]()
|
||||||
let group = DispatchGroup()
|
let group = DispatchGroup()
|
||||||
|
|
||||||
activeAccounts.forEach { account in
|
for account in activeAccounts {
|
||||||
group.enter()
|
group.enter()
|
||||||
account.refreshAll() { result in
|
account.refreshAll() { result in
|
||||||
group.leave()
|
group.leave()
|
||||||
@ -297,9 +305,9 @@ public final class AccountManager: UnreadCountProvider {
|
|||||||
public func sendArticleStatusAll(completion: (() -> Void)? = nil) {
|
public func sendArticleStatusAll(completion: (() -> Void)? = nil) {
|
||||||
let group = DispatchGroup()
|
let group = DispatchGroup()
|
||||||
|
|
||||||
activeAccounts.forEach {
|
for account in activeAccounts {
|
||||||
group.enter()
|
group.enter()
|
||||||
$0.sendArticleStatus() { _ in
|
account.sendArticleStatus() { _ in
|
||||||
group.leave()
|
group.leave()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -312,9 +320,9 @@ public final class AccountManager: UnreadCountProvider {
|
|||||||
public func syncArticleStatusAll(completion: (() -> Void)? = nil) {
|
public func syncArticleStatusAll(completion: (() -> Void)? = nil) {
|
||||||
let group = DispatchGroup()
|
let group = DispatchGroup()
|
||||||
|
|
||||||
activeAccounts.forEach {
|
for account in activeAccounts {
|
||||||
group.enter()
|
group.enter()
|
||||||
$0.syncArticleStatus() { _ in
|
account.syncArticleStatus() { _ in
|
||||||
group.leave()
|
group.leave()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -325,7 +333,9 @@ public final class AccountManager: UnreadCountProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func saveAll() {
|
public func saveAll() {
|
||||||
accounts.forEach { $0.save() }
|
for account in accounts {
|
||||||
|
account.save()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func anyAccountHasAtLeastOneFeed() -> Bool {
|
public func anyAccountHasAtLeastOneFeed() -> Bool {
|
||||||
@ -481,9 +491,10 @@ private extension AccountManager {
|
|||||||
|
|
||||||
filenames = filenames?.sorted()
|
filenames = filenames?.sorted()
|
||||||
|
|
||||||
filenames?.forEach { (oneFilename) in
|
if let filenames {
|
||||||
|
for oneFilename in filenames {
|
||||||
guard oneFilename != defaultAccountFolderName else {
|
guard oneFilename != defaultAccountFolderName else {
|
||||||
return
|
continue
|
||||||
}
|
}
|
||||||
if let oneAccount = loadAccount(oneFilename) {
|
if let oneAccount = loadAccount(oneFilename) {
|
||||||
if !duplicateServiceAccount(oneAccount) {
|
if !duplicateServiceAccount(oneAccount) {
|
||||||
@ -492,6 +503,7 @@ private extension AccountManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func duplicateServiceAccount(_ account: Account) -> Bool {
|
func duplicateServiceAccount(_ account: Account) -> Bool {
|
||||||
return duplicateServiceAccount(type: account.type, username: account.username)
|
return duplicateServiceAccount(type: account.type, username: account.username)
|
||||||
|
@ -77,7 +77,8 @@ final class CloudKitAccountZone: CloudKitZone {
|
|||||||
if let title = item.titleFromAttributes {
|
if let title = item.titleFromAttributes {
|
||||||
let containerRecord = newContainerCKRecord(name: title)
|
let containerRecord = newContainerCKRecord(name: title)
|
||||||
records.append(containerRecord)
|
records.append(containerRecord)
|
||||||
item.items?.forEach { itemChild in
|
if let items = item.items {
|
||||||
|
for itemChild in items {
|
||||||
if let feedSpecifier = itemChild.feedSpecifier {
|
if let feedSpecifier = itemChild.feedSpecifier {
|
||||||
processFeed(feedSpecifier: feedSpecifier, containerExternalID: containerRecord.externalID)
|
processFeed(feedSpecifier: feedSpecifier, containerExternalID: containerRecord.externalID)
|
||||||
}
|
}
|
||||||
@ -85,6 +86,7 @@ final class CloudKitAccountZone: CloudKitZone {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
save(records, completion: completion)
|
save(records, completion: completion)
|
||||||
}
|
}
|
||||||
|
@ -84,9 +84,9 @@ class CloudKitAcountZoneDelegate: CloudKitZoneDelegate {
|
|||||||
|
|
||||||
func removeFeed(_ externalID: String) {
|
func removeFeed(_ externalID: String) {
|
||||||
if let feed = account?.existingFeed(withExternalID: externalID), let containers = account?.existingContainers(withFeed: feed) {
|
if let feed = account?.existingFeed(withExternalID: externalID), let containers = account?.existingContainers(withFeed: feed) {
|
||||||
containers.forEach {
|
for container in containers {
|
||||||
feed.dropConditionalGetInfo()
|
feed.dropConditionalGetInfo()
|
||||||
$0.removeFeed(feed)
|
container.removeFeed(feed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,9 @@ final class FeedMetadataFile {
|
|||||||
let decoder = PropertyListDecoder()
|
let decoder = PropertyListDecoder()
|
||||||
account.feedMetadata = (try? decoder.decode(Account.FeedMetadataDictionary.self, from: fileData)) ?? Account.FeedMetadataDictionary()
|
account.feedMetadata = (try? decoder.decode(Account.FeedMetadataDictionary.self, from: fileData)) ?? Account.FeedMetadataDictionary()
|
||||||
}
|
}
|
||||||
account.feedMetadata.values.forEach { $0.delegate = account }
|
for value in account.feedMetadata.values {
|
||||||
|
value.delegate = account
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func save() {
|
func save() {
|
||||||
|
@ -761,7 +761,7 @@ private extension FeedbinAccountDelegate {
|
|||||||
// Feedbin has a tag that we don't have a folder for. We might not get a new
|
// Feedbin has a tag that we don't have a folder for. We might not get a new
|
||||||
// taggings response for it if it is a folder rename. Force expire the tagging
|
// taggings response for it if it is a folder rename. Force expire the tagging
|
||||||
// so that we will for sure get the new tagging information.
|
// so that we will for sure get the new tagging information.
|
||||||
tags.forEach { tag in
|
for tag in tags {
|
||||||
if !folderNames.contains(tag.name) {
|
if !folderNames.contains(tag.name) {
|
||||||
accountMetadata?.conditionalGetInfo[FeedbinAPICaller.ConditionalGetKeys.taggings] = nil
|
accountMetadata?.conditionalGetInfo[FeedbinAPICaller.ConditionalGetKeys.taggings] = nil
|
||||||
}
|
}
|
||||||
@ -779,7 +779,7 @@ private extension FeedbinAccountDelegate {
|
|||||||
|
|
||||||
// Delete any folders not at Feedbin
|
// Delete any folders not at Feedbin
|
||||||
if let folders = account.folders {
|
if let folders = account.folders {
|
||||||
folders.forEach { folder in
|
for folder in folders {
|
||||||
if !tagNames.contains(folder.name ?? "") {
|
if !tagNames.contains(folder.name ?? "") {
|
||||||
for feed in folder.topLevelFeeds {
|
for feed in folder.topLevelFeeds {
|
||||||
account.addFeed(feed)
|
account.addFeed(feed)
|
||||||
@ -799,7 +799,7 @@ private extension FeedbinAccountDelegate {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// Make any folders Feedbin has, but we don't
|
// Make any folders Feedbin has, but we don't
|
||||||
tagNames.forEach { tagName in
|
for tagName in tagNames {
|
||||||
if !folderNames.contains(tagName) {
|
if !folderNames.contains(tagName) {
|
||||||
_ = account.ensureFolder(with: tagName)
|
_ = account.ensureFolder(with: tagName)
|
||||||
}
|
}
|
||||||
@ -835,7 +835,7 @@ private extension FeedbinAccountDelegate {
|
|||||||
|
|
||||||
// Add any feeds we don't have and update any we do
|
// Add any feeds we don't have and update any we do
|
||||||
var subscriptionsToAdd = Set<FeedbinSubscription>()
|
var subscriptionsToAdd = Set<FeedbinSubscription>()
|
||||||
subscriptions.forEach { subscription in
|
for subscription in subscriptions {
|
||||||
|
|
||||||
let subFeedId = String(subscription.feedID)
|
let subFeedId = String(subscription.feedID)
|
||||||
|
|
||||||
@ -854,7 +854,7 @@ private extension FeedbinAccountDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Actually add subscriptions all in one go, so we don’t trigger various rebuilding things that Account does.
|
// Actually add subscriptions all in one go, so we don’t trigger various rebuilding things that Account does.
|
||||||
subscriptionsToAdd.forEach { subscription in
|
for subscription in subscriptionsToAdd {
|
||||||
let feed = account.createFeed(with: subscription.name, url: subscription.url, feedID: String(subscription.feedID), homePageURL: subscription.homePageURL)
|
let feed = account.createFeed(with: subscription.name, url: subscription.url, feedID: String(subscription.feedID), homePageURL: subscription.homePageURL)
|
||||||
feed.externalID = String(subscription.subscriptionID)
|
feed.externalID = String(subscription.subscriptionID)
|
||||||
account.addFeed(feed)
|
account.addFeed(feed)
|
||||||
|
@ -95,7 +95,7 @@ final class FeedlyCreateFeedsForCollectionFoldersOperation: FeedlyOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
os_log(.debug, log: log, "Processing %i feeds.", feedsAndFolders.count)
|
os_log(.debug, log: log, "Processing %i feeds.", feedsAndFolders.count)
|
||||||
feedsAndFolders.forEach { (feed, folder) in
|
for (feed, folder) in feedsAndFolders {
|
||||||
if !folder.has(feed) {
|
if !folder.has(feed) {
|
||||||
folder.addFeed(feed)
|
folder.addFeed(feed)
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ extension NewsBlurAccountDelegate {
|
|||||||
|
|
||||||
// Delete any folders not at NewsBlur
|
// Delete any folders not at NewsBlur
|
||||||
if let folders = account.folders {
|
if let folders = account.folders {
|
||||||
folders.forEach { folder in
|
for folder in folders {
|
||||||
if !folderNames.contains(folder.name ?? "") {
|
if !folderNames.contains(folder.name ?? "") {
|
||||||
for feed in folder.topLevelFeeds {
|
for feed in folder.topLevelFeeds {
|
||||||
account.addFeed(feed)
|
account.addFeed(feed)
|
||||||
@ -67,7 +67,7 @@ extension NewsBlurAccountDelegate {
|
|||||||
|
|
||||||
// Make any folders NewsBlur has, but we don't
|
// Make any folders NewsBlur has, but we don't
|
||||||
// Ignore account-level folder
|
// Ignore account-level folder
|
||||||
folderNames.forEach { folderName in
|
for folderName in folderNames {
|
||||||
if !accountFolderNames.contains(folderName) && folderName != " " {
|
if !accountFolderNames.contains(folderName) && folderName != " " {
|
||||||
_ = account.ensureFolder(with: folderName)
|
_ = account.ensureFolder(with: folderName)
|
||||||
}
|
}
|
||||||
@ -118,8 +118,8 @@ extension NewsBlurAccountDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Actually add feeds all in one go, so we don’t trigger various rebuilding things that Account does.
|
// Actually add feeds all in one go, so we don’t trigger various rebuilding things that Account does.
|
||||||
feedsToAdd.forEach { feed in
|
for feedToAdd in feedsToAdd {
|
||||||
let feed = account.createFeed(with: feed.name, url: feed.feedURL, feedID: String(feed.feedID), homePageURL: feed.homePageURL)
|
let feed = account.createFeed(with: feedToAdd.name, url: feedToAdd.feedURL, feedID: String(feedToAdd.feedID), homePageURL: feedToAdd.homePageURL)
|
||||||
feed.externalID = String(feed.feedID)
|
feed.externalID = String(feed.feedID)
|
||||||
account.addFeed(feed)
|
account.addFeed(feed)
|
||||||
}
|
}
|
||||||
|
@ -22,13 +22,13 @@ final class OPMLNormalizer {
|
|||||||
private func normalize(_ items: [OPMLItem], parentFolder: OPMLItem? = nil) {
|
private func normalize(_ items: [OPMLItem], parentFolder: OPMLItem? = nil) {
|
||||||
var feedsToAdd = [OPMLItem]()
|
var feedsToAdd = [OPMLItem]()
|
||||||
|
|
||||||
items.forEach { (item) in
|
for item in items {
|
||||||
|
|
||||||
if let _ = item.feedSpecifier {
|
if let _ = item.feedSpecifier {
|
||||||
if !feedsToAdd.contains(where: { $0.feedSpecifier?.feedURL == item.feedSpecifier?.feedURL }) {
|
if !feedsToAdd.contains(where: { $0.feedSpecifier?.feedURL == item.feedSpecifier?.feedURL }) {
|
||||||
feedsToAdd.append(item)
|
feedsToAdd.append(item)
|
||||||
}
|
}
|
||||||
return
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let _ = item.titleFromAttributes else {
|
guard let _ = item.titleFromAttributes else {
|
||||||
@ -36,7 +36,7 @@ final class OPMLNormalizer {
|
|||||||
if let itemChildren = item.items {
|
if let itemChildren = item.items {
|
||||||
normalize(itemChildren, parentFolder: parentFolder)
|
normalize(itemChildren, parentFolder: parentFolder)
|
||||||
}
|
}
|
||||||
return
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
feedsToAdd.append(item)
|
feedsToAdd.append(item)
|
||||||
@ -60,7 +60,5 @@ final class OPMLNormalizer {
|
|||||||
normalizedOPMLItems.append(feed)
|
normalizedOPMLItems.append(feed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -718,7 +718,7 @@ private extension ReaderAPIAccountDelegate {
|
|||||||
|
|
||||||
// Delete any folders not at Reader
|
// Delete any folders not at Reader
|
||||||
if let folders = account.folders {
|
if let folders = account.folders {
|
||||||
folders.forEach { folder in
|
for folder in folders {
|
||||||
if !readerFolderExternalIDs.contains(folder.externalID ?? "") {
|
if !readerFolderExternalIDs.contains(folder.externalID ?? "") {
|
||||||
for feed in folder.topLevelFeeds {
|
for feed in folder.topLevelFeeds {
|
||||||
account.addFeed(feed)
|
account.addFeed(feed)
|
||||||
@ -738,7 +738,7 @@ private extension ReaderAPIAccountDelegate {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// Make any folders Reader has, but we don't
|
// Make any folders Reader has, but we don't
|
||||||
folderTags.forEach { tag in
|
for tag in folderTags {
|
||||||
if !folderExternalIDs.contains(tag.tagID) {
|
if !folderExternalIDs.contains(tag.tagID) {
|
||||||
let folder = account.ensureFolder(with: tag.folderName ?? "None")
|
let folder = account.ensureFolder(with: tag.folderName ?? "None")
|
||||||
folder?.externalID = tag.tagID
|
folder?.externalID = tag.tagID
|
||||||
@ -775,7 +775,7 @@ private extension ReaderAPIAccountDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add any feeds we don't have and update any we do
|
// Add any feeds we don't have and update any we do
|
||||||
subscriptions.forEach { subscription in
|
for subscription in subscriptions {
|
||||||
|
|
||||||
if let feed = account.existingFeed(withFeedID: subscription.feedID) {
|
if let feed = account.existingFeed(withFeedID: subscription.feedID) {
|
||||||
feed.name = subscription.name
|
feed.name = subscription.name
|
||||||
@ -801,14 +801,14 @@ private extension ReaderAPIAccountDelegate {
|
|||||||
let taggingsDict = subscriptions.reduce([String: [ReaderAPISubscription]]()) { (dict, subscription) in
|
let taggingsDict = subscriptions.reduce([String: [ReaderAPISubscription]]()) { (dict, subscription) in
|
||||||
var taggedFeeds = dict
|
var taggedFeeds = dict
|
||||||
|
|
||||||
subscription.categories.forEach({ (category) in
|
for category in subscription.categories {
|
||||||
if var taggedFeed = taggedFeeds[category.categoryId] {
|
if var taggedFeed = taggedFeeds[category.categoryId] {
|
||||||
taggedFeed.append(subscription)
|
taggedFeed.append(subscription)
|
||||||
taggedFeeds[category.categoryId] = taggedFeed
|
taggedFeeds[category.categoryId] = taggedFeed
|
||||||
} else {
|
} else {
|
||||||
taggedFeeds[category.categoryId] = [subscription]
|
taggedFeeds[category.categoryId] = [subscription]
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
return taggedFeeds
|
return taggedFeeds
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,9 @@ final class SearchTable: DatabaseTable {
|
|||||||
private extension SearchTable {
|
private extension SearchTable {
|
||||||
|
|
||||||
func performInitialIndexForArticles(_ articles: Set<ArticleSearchInfo>, _ database: FMDatabase) {
|
func performInitialIndexForArticles(_ articles: Set<ArticleSearchInfo>, _ database: FMDatabase) {
|
||||||
articles.forEach { performInitialIndex($0, database) }
|
for article in articles {
|
||||||
|
performInitialIndex(article, database)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func performInitialIndex(_ article: ArticleSearchInfo, _ database: FMDatabase) {
|
func performInitialIndex(_ article: ArticleSearchInfo, _ database: FMDatabase) {
|
||||||
@ -177,7 +179,7 @@ private extension SearchTable {
|
|||||||
let groupedSearchInfos = Dictionary(grouping: searchInfos, by: { $0.rowID })
|
let groupedSearchInfos = Dictionary(grouping: searchInfos, by: { $0.rowID })
|
||||||
let searchInfosDictionary = groupedSearchInfos.mapValues { $0.first! }
|
let searchInfosDictionary = groupedSearchInfos.mapValues { $0.first! }
|
||||||
|
|
||||||
articles.forEach { (article) in
|
for article in articles {
|
||||||
updateIndexForArticle(article, searchInfosDictionary, database)
|
updateIndexForArticle(article, searchInfosDictionary, database)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,9 @@ struct QueueCall: Equatable {
|
|||||||
guard !isPaused else { return }
|
guard !isPaused else { return }
|
||||||
let callsToMake = calls // Make a copy in case calls are added to the queue while performing calls.
|
let callsToMake = calls // Make a copy in case calls are added to the queue while performing calls.
|
||||||
resetCalls()
|
resetCalls()
|
||||||
callsToMake.forEach { $0.perform() }
|
for call in callsToMake {
|
||||||
|
call.perform()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func timerDidFire(_ sender: Any?) {
|
@objc func timerDidFire(_ sender: Any?) {
|
||||||
|
@ -68,7 +68,9 @@ public final class MainThreadOperationQueue {
|
|||||||
/// Add multiple operations to the queue.
|
/// Add multiple operations to the queue.
|
||||||
/// This has the same effect as calling addOperation one-by-one.
|
/// This has the same effect as calling addOperation one-by-one.
|
||||||
public func addOperations(_ operations: [MainThreadOperation]) {
|
public func addOperations(_ operations: [MainThreadOperation]) {
|
||||||
operations.forEach{ add($0) }
|
for operation in operations {
|
||||||
|
add(operation)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a dependency. Do this *before* calling addOperation, since addOperation might run the operation right away.
|
/// Add a dependency. Do this *before* calling addOperation, since addOperation might run the operation right away.
|
||||||
@ -453,16 +455,22 @@ private extension MainThreadOperationDependencies {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func removeDependencies(_ parentOperationIDs: [Int]) {
|
func removeDependencies(_ parentOperationIDs: [Int]) {
|
||||||
parentOperationIDs.forEach { dependencies[$0] = nil }
|
for parentOperationID in parentOperationIDs {
|
||||||
|
dependencies[parentOperationID] = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeChildOperationIDs(_ operationIDs: [Int]) {
|
func removeChildOperationIDs(_ operationIDs: [Int]) {
|
||||||
operationIDs.forEach{ removeChildOperationID($0) }
|
for operationID in operationIDs {
|
||||||
|
removeChildOperationID(operationID)
|
||||||
|
}
|
||||||
removeEmptyDependencies()
|
removeEmptyDependencies()
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeChildOperationID(_ operationID: Int) {
|
func removeChildOperationID(_ operationID: Int) {
|
||||||
dependencies.values.forEach{ $0.remove(operationID) }
|
for value in dependencies.values {
|
||||||
|
value.remove(operationID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeEmptyDependencies() {
|
func removeEmptyDependencies() {
|
||||||
|
@ -67,10 +67,12 @@ public extension UndoableCommandRunner {
|
|||||||
// Otherwise things like Redo Mark Read are ambiguous.
|
// Otherwise things like Redo Mark Read are ambiguous.
|
||||||
// (Do they apply to the previous articles or to the current articles?)
|
// (Do they apply to the previous articles or to the current articles?)
|
||||||
|
|
||||||
guard let undoManager = undoManager else {
|
guard let undoManager else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
undoableCommands.forEach { undoManager.removeAllActions(withTarget: $0) }
|
for undoableCommand in undoableCommands {
|
||||||
|
undoManager.removeAllActions(withTarget: undoableCommand)
|
||||||
|
}
|
||||||
undoableCommands = [UndoableCommand]()
|
undoableCommands = [UndoableCommand]()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,12 @@ extension UIViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func replaceChildAndPinView(_ controller: UIViewController) {
|
public func replaceChildAndPinView(_ controller: UIViewController) {
|
||||||
view.subviews.forEach { $0.removeFromSuperview() }
|
for subview in view.subviews {
|
||||||
children.forEach { $0.removeFromParent() }
|
subview.removeFromSuperview()
|
||||||
|
}
|
||||||
|
for child in children {
|
||||||
|
child.removeFromParent()
|
||||||
|
}
|
||||||
addChildAndPinView(controller)
|
addChildAndPinView(controller)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ public extension DatabaseTable {
|
|||||||
|
|
||||||
func insertRows(_ dictionaries: [DatabaseDictionary], insertType: RSDatabaseInsertType, in database: FMDatabase) {
|
func insertRows(_ dictionaries: [DatabaseDictionary], insertType: RSDatabaseInsertType, in database: FMDatabase) {
|
||||||
|
|
||||||
dictionaries.forEach { (oneDictionary) in
|
for oneDictionary in dictionaries {
|
||||||
let _ = database.rs_insertRow(with: oneDictionary, insertType: insertType, tableName: self.name)
|
let _ = database.rs_insertRow(with: oneDictionary, insertType: insertType, tableName: self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@ private extension TreeController {
|
|||||||
func visitNode(_ node: Node, _ visitBlock: NodeVisitBlock) {
|
func visitNode(_ node: Node, _ visitBlock: NodeVisitBlock) {
|
||||||
|
|
||||||
visitBlock(node)
|
visitBlock(node)
|
||||||
node.childNodes.forEach{ (oneChildNode) in
|
for oneChildNode in node.childNodes {
|
||||||
visitNode(oneChildNode, visitBlock)
|
visitNode(oneChildNode, visitBlock)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -124,7 +124,7 @@ private extension TreeController {
|
|||||||
node.childNodes = childNodes
|
node.childNodes = childNodes
|
||||||
}
|
}
|
||||||
|
|
||||||
childNodes.forEach{ (oneChildNode) in
|
for oneChildNode in childNodes {
|
||||||
if rebuildChildNodes(node: oneChildNode) {
|
if rebuildChildNodes(node: oneChildNode) {
|
||||||
childNodesDidChange = true
|
childNodesDidChange = true
|
||||||
}
|
}
|
||||||
|
@ -64,9 +64,15 @@ public protocol DownloadSessionDelegate {
|
|||||||
|
|
||||||
public func cancelAll() {
|
public func cancelAll() {
|
||||||
urlSession.getTasksWithCompletionHandler { dataTasks, uploadTasks, downloadTasks in
|
urlSession.getTasksWithCompletionHandler { dataTasks, uploadTasks, downloadTasks in
|
||||||
dataTasks.forEach { $0.cancel() }
|
for dataTask in dataTasks {
|
||||||
uploadTasks.forEach { $0.cancel() }
|
dataTask.cancel()
|
||||||
downloadTasks.forEach { $0.cancel() }
|
}
|
||||||
|
for uploadTask in uploadTasks {
|
||||||
|
uploadTask.cancel()
|
||||||
|
}
|
||||||
|
for downloadTask in downloadTasks {
|
||||||
|
downloadTask.cancel()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,11 +28,11 @@ public struct HTTPLinkPagingInfo {
|
|||||||
let links = linkHeader.components(separatedBy: ",")
|
let links = linkHeader.components(separatedBy: ",")
|
||||||
|
|
||||||
var dict: [String: String] = [:]
|
var dict: [String: String] = [:]
|
||||||
links.forEach({
|
for link in links {
|
||||||
let components = $0.components(separatedBy:"; ")
|
let components = link.components(separatedBy:"; ")
|
||||||
let page = components[0].trimmingCharacters(in: CharacterSet(charactersIn: " <>"))
|
let page = components[0].trimmingCharacters(in: CharacterSet(charactersIn: " <>"))
|
||||||
dict[components[1]] = page
|
dict[components[1]] = page
|
||||||
})
|
}
|
||||||
|
|
||||||
self.init(nextPage: dict["rel=\"next\""], lastPage: dict["rel=\"last\""])
|
self.init(nextPage: dict["rel=\"next\""], lastPage: dict["rel=\"last\""])
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ private final class WebCache {
|
|||||||
func cleanup(_ cleanupInterval: TimeInterval) {
|
func cleanup(_ cleanupInterval: TimeInterval) {
|
||||||
|
|
||||||
let cutoffDate = Date(timeInterval: -cleanupInterval, since: Date())
|
let cutoffDate = Date(timeInterval: -cleanupInterval, since: Date())
|
||||||
cache.keys.forEach { (key) in
|
for key in cache.keys {
|
||||||
let cacheRecord = self[key]!
|
let cacheRecord = self[key]!
|
||||||
if shouldDelete(cacheRecord, cutoffDate) {
|
if shouldDelete(cacheRecord, cutoffDate) {
|
||||||
cache[key] = nil
|
cache[key] = nil
|
||||||
@ -168,7 +168,7 @@ private final class DownloadWithCacheManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var callbackCount = 0
|
var callbackCount = 0
|
||||||
self.pendingCallbacks.forEach{ (callbackRecord) in
|
for callbackRecord in self.pendingCallbacks {
|
||||||
if url == callbackRecord.url {
|
if url == callbackRecord.url {
|
||||||
callbackRecord.completion(data, response, error)
|
callbackRecord.completion(data, response, error)
|
||||||
callbackCount += 1
|
callbackCount += 1
|
||||||
|
@ -134,9 +134,15 @@ extension URLSession: Transport {
|
|||||||
|
|
||||||
public func cancelAll() {
|
public func cancelAll() {
|
||||||
getTasksWithCompletionHandler { dataTasks, uploadTasks, downloadTasks in
|
getTasksWithCompletionHandler { dataTasks, uploadTasks, downloadTasks in
|
||||||
dataTasks.forEach { $0.cancel() }
|
for dataTask in dataTasks {
|
||||||
uploadTasks.forEach { $0.cancel() }
|
dataTask.cancel()
|
||||||
downloadTasks.forEach { $0.cancel() }
|
}
|
||||||
|
for uploadTask in uploadTasks {
|
||||||
|
uploadTask.cancel()
|
||||||
|
}
|
||||||
|
for downloadTask in downloadTasks {
|
||||||
|
downloadTask.cancel()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ final class SmartFeed: PseudoFeed {
|
|||||||
|
|
||||||
// Remove any accounts that are no longer active or have been deleted
|
// Remove any accounts that are no longer active or have been deleted
|
||||||
let activeAccountIDs = activeAccounts.map { $0.accountID }
|
let activeAccountIDs = activeAccounts.map { $0.accountID }
|
||||||
unreadCounts.keys.forEach { accountID in
|
for accountID in unreadCounts.keys {
|
||||||
if !activeAccountIDs.contains(accountID) {
|
if !activeAccountIDs.contains(accountID) {
|
||||||
unreadCounts.removeValue(forKey: accountID)
|
unreadCounts.removeValue(forKey: accountID)
|
||||||
}
|
}
|
||||||
@ -75,7 +75,9 @@ final class SmartFeed: PseudoFeed {
|
|||||||
if activeAccounts.isEmpty {
|
if activeAccounts.isEmpty {
|
||||||
updateUnreadCount()
|
updateUnreadCount()
|
||||||
} else {
|
} else {
|
||||||
activeAccounts.forEach { self.fetchUnreadCount(for: $0) }
|
for account in activeAccounts {
|
||||||
|
self.fetchUnreadCount(for: account)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,9 @@ final class FetchRequestQueue {
|
|||||||
|
|
||||||
func cancelAllRequests() {
|
func cancelAllRequests() {
|
||||||
precondition(Thread.isMainThread)
|
precondition(Thread.isMainThread)
|
||||||
pendingRequests.forEach { $0.isCanceled = true }
|
for request in pendingRequests {
|
||||||
|
request.isCanceled = true
|
||||||
|
}
|
||||||
currentRequest?.isCanceled = true
|
currentRequest?.isCanceled = true
|
||||||
pendingRequests = [FetchRequestOperation]()
|
pendingRequests = [FetchRequestOperation]()
|
||||||
}
|
}
|
||||||
|
@ -82,12 +82,12 @@ private extension FeedTreeControllerDelegate {
|
|||||||
|
|
||||||
var updatedChildNodes = [Node]()
|
var updatedChildNodes = [Node]()
|
||||||
|
|
||||||
children.forEach { (representedObject) in
|
for representedObject in children {
|
||||||
|
|
||||||
if let existingNode = containerNode.childNodeRepresentingObject(representedObject) {
|
if let existingNode = containerNode.childNodeRepresentingObject(representedObject) {
|
||||||
if !updatedChildNodes.contains(existingNode) {
|
if !updatedChildNodes.contains(existingNode) {
|
||||||
updatedChildNodes += [existingNode]
|
updatedChildNodes += [existingNode]
|
||||||
return
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,7 +452,8 @@ class TimelineViewController: UITableViewController, UndoableCommandRunner {
|
|||||||
guard let feed = note.userInfo?[UserInfoKey.feed] as? Feed else {
|
guard let feed = note.userInfo?[UserInfoKey.feed] as? Feed else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for indexPath in tableView.indexPathsForVisibleRows? {
|
if let indexPaths = tableView.indexPathsForVisibleRows {
|
||||||
|
for indexPath in indexPaths {
|
||||||
guard let article = dataSource.itemIdentifier(for: indexPath) else {
|
guard let article = dataSource.itemIdentifier(for: indexPath) else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -461,12 +462,14 @@ class TimelineViewController: UITableViewController, UndoableCommandRunner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@objc func avatarDidBecomeAvailable(_ note: Notification) {
|
@objc func avatarDidBecomeAvailable(_ note: Notification) {
|
||||||
guard coordinator.showIcons, let avatarURL = note.userInfo?[UserInfoKey.url] as? String else {
|
guard coordinator.showIcons, let avatarURL = note.userInfo?[UserInfoKey.url] as? String else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for indexPath in tableView.indexPathsForVisibleRows? {
|
if let indexPaths = tableView.indexPathsForVisibleRows {
|
||||||
|
for indexPath in indexPaths {
|
||||||
guard let article = dataSource.itemIdentifier(for: indexPath), let authors = article.authors, !authors.isEmpty else {
|
guard let article = dataSource.itemIdentifier(for: indexPath), let authors = article.authors, !authors.isEmpty else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -477,6 +480,7 @@ class TimelineViewController: UITableViewController, UndoableCommandRunner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@objc func faviconDidBecomeAvailable(_ note: Notification) {
|
@objc func faviconDidBecomeAvailable(_ note: Notification) {
|
||||||
if let titleView = navigationItem.titleView as? TimelineTitleView {
|
if let titleView = navigationItem.titleView as? TimelineTitleView {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user