100 Days of Swift & Hacking with iOS UIKit 版關鍵字重點整理

Paul Hudson 大大在網路上撰寫許多適合初學者學習的 iOS App 開發教材,彼得潘平時也常跟 Paul 學習。

想學習 iOS UIKit App 開發,Paul 的 100 Days of Swift & Hacking with iOS UIKit 版十分值得一讀。100 Days of Swift 包含了 30 個不同主題的 project。

Hacking with iOS 則包含 39 個 project,前 30 個是 100 Days of Swift 的 project,然後再加碼 9 個額外的 project。

有興趣的朋友可參考以上連結仔細研讀 Paul 的文章和影片,如果已有一定基礎,也可從 GitHub 下載專案的程式快速研究。

  • Paul 大大官方版的範例程式

HackingWithSwift 下分成 UIKit & SwiftUI 兩個版本,UIKit 版在資料夾 Classic 下。

  • Khumar 的範例程式

Pual 網頁上的教學有更新,不過官方 GitHub 的程式有些仍是舊的版本,新版可參考 Khumar 的連結。

最近彼得潘也花了點時間研究這 39 個專案,以下一一列出它們的關鍵字重點整理 & App 畫面,歡迎有興趣的朋友參考。

ps:

  • 彼得潘在整理關鍵字時,主要將它列在第一次出現的 project。比方 IBOutlet 初次出現在 project 1,因此將它列在 project 1,之後的 project 即使有用到 IBOutlet 也不會列出。
  • 39 個專案裡有 10 個跟遊戲相關的主題,跟 SpriteKit 技術有關。以下特別將這 10 個 project 的名稱加上(Game),對遊戲開發沒興趣的朋友可先跳過。
  • 39 個專案裡有許多技術是工作一兩年的 iOS 工程師也不一定會接觸的,想轉職新手 iOS App 工程師的朋友可先目標研究以下專案:

1~10,12~13,15~16,18~19,21,24,27~28,31~32,38。

Project 1: Storm Viewer

關鍵技術:

Xcode,project,UIKit,Interface Builder,storyboard,swift,UIViewController,title,viewDidLoad,viewWillAppear,viewWillDisappear,FileManager,Bundle.main,resourcePath,contentsOfDirectory,UITableViewController,data source,UITableView,UITableViewCell,delegate,UITableViewDataSource,UITableViewDelegate,tableView(_:numberOfRowsInSection:),tableView(_:cellForRowAt:),cell reuse id,dequeueReusableCell(withIdentifier:for:),IndexPath,row,textLabel,tableView(_:didSelectRowAt:),IBOutlet,UIImageView,aspect fit,UIImage,UINavigationController,navigationController,navigationBar,hidesBarsOnTap,pushViewController,storyboard id,instantiateViewController(withIdentifier:),prefersLargeTitles,navigationItem,largeTitleDisplayMode,Auto Layout,constraint

Project 2: Guess the Flag

關鍵技術:

asset catalogs,UIButton,append,setImage(_:for:),UIControlState,normal,UIView,CALayer,layer,borderWidth,borderColor,UIColor,CGColor,IBAction,tag,shuffle,random,UIAlertController,alert,UIAlertAction,addAction,present(_:animated:completion:),uppercased,2x,3x

Project 3: Social Media

關鍵技術:

UIBarButtonItem,rightBarButtonItem,#selector,@objc,UIActivityViewController,share,jpegData(compressionQuality:),popoverPresentationController?.barButtonItem,Info,Privacy — Photo Library Additions Usage Description

ps: 網頁的教學有更新,官方範例裡的 shareTapped 請更新成以下版本,並在 App 的 Info 頁面加入 Privacy — Photo Library Additions Usage Description。

@objc func shareTapped() {
guard let image = imageView.image?.jpegData(compressionQuality: 0.8) else {
print("No image found")
return
}
let vc = UIActivityViewController(activityItems: [image], applicationActivities: [])
vc.popoverPresentationController?.barButtonItem = navigationItem.rightBarButtonItem
present(vc, animated: true)
}

Project 4: Easy Browser

關鍵技術:

WebKit,WKWebView,WKNavigationDelegate,loadView,URL,URLRequest,load,allowsBackForwardNavigationGestures,actionSheet,UIProgressView,sizeToFit,flexibleSpace,UIToolbar,toolbarItems,isToolbarHidden,KVO,key value observing,addObserver(_:forKeyPath:options:context:),#keyPath(WKWebView.estimatedProgress),webView(_:didFinish:),webView(_:decidePolicyFor:decisionHandler:),observeValue(forKeyPath:of:change:context:),contains

Project 5: Word Scramble

關鍵技術:

capture list,strong,weak,unowned,strong reference cycle,retain cycle,path(forResource:ofType:),String(contentsOfFile:),components(separatedBy:),randomElement,reloadData,addTextField,textFields,range(of:),firstIndex(of:),UITextChecker,rangeOfMisspelledWord,insertRows,lowercased,NSRange,NSNotFound,utf16

ps: 網頁的教學有更新,官方範例裡的 isPossible & isReal 請更新成以下版本。

func isPossible(word: String) -> Bool {
guard var tempWord = title?.lowercased() else { return false }
for letter in word {
if let position = tempWord.firstIndex(of: letter) {
tempWord.remove(at: position)
} else {
return false
}
}
return true
}
func isReal(word: String) -> Bool {
let checker = UITextChecker()
let range = NSRange(location: 0, length: word.utf16.count)
let misspelledRange = checker.rangeOfMisspelledWord(in: word, range: range, startingAt: 0, wrap: false, language: "en")
return misspelledRange.location == NSNotFound
}

Project 6: Auto Layout

關鍵技術:

addSubview,aspect ratio,NSLayoutConstraint,translatesAutoresizingMaskIntoConstraints,visual format language,constraints(withVisualFormat:options:metrics:views:),addConstraints,NSLayoutAnchor,constraint(equalTo:constant:),isActive,prefersStatusBarHidden

Project 7: Whitehouse Petitions

關鍵技術:

UITabBarController,Data,Data(contentsOf:),network,JSON,Codable,JSONDecoder,decode(_:from:),loadHTMLString(_:baseURL:),AppDelegate,application(_:didFinishLaunchingWithOptions:),UIWindow,window,rootViewController,UIStoryboard,UIStoryboard(name:bundle:),UITabBarItem,UITabBarItem(tabBarSystemItem:tag:),SceneDelegate,scene(_:willConnectTo:options:)

ps:

  • ViewController 裡記得改成以下網址
if navigationController?.tabBarItem.tag == 0 {
urlString = "https://www.hackingwithswift.com/samples/petitions-1.json"
} else {
urlString = "https://www.hackingwithswift.com/samples/petitions-2.json"
}
  • 新版 Xcode 專案多了 SceneDelegate.swift,請在 SceneDelegate 的 scene(_:willConnectTo:options:) 加入以下程式。
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let _ = (scene as? UIWindowScene) else { return }
if let tabBarController = window?.rootViewController as? UITabBarController {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "NavController")
vc.tabBarItem = UITabBarItem(tabBarSystemItem: .topRated, tag: 1)
tabBarController.viewControllers?.append(vc)
}
}

Project 8: 7 Swifty Words

關鍵技術:

iPad,layoutMarginsGuide,activate,addTarget(_:action:for:),touchUpInside,subviews,isHidden,enumerated,tuple,replacingOccurrences(of:with:),trimmingCharacters(in:),whitespacesAndNewlines,setTitle(_:for:),joined,UIFont,isUserInteractionEnabled,placeholder,setContentHuggingPriority(_:for:),UILayoutPriority,vertical,horizontal,CGRect,frame,didSet,property observer,removeAll

ps: 網頁的教學有更新,改成從程式製作畫面,新版的程式可參考 Khumar 的 GitHub。

Project 9: Grand Central Dispatch

關鍵技術:

GCD,grand central dispatch,async,DispatchQueue,main,global,qos,performSelector(inBackground:),performSelector(onMainThread:with:waitUntilDone:)

ps: ViewController 裡記得改成以下網址

if navigationController?.tabBarItem.tag == 0 {
urlString = "https://www.hackingwithswift.com/samples/petitions-1.json"
} else {
urlString = "https://www.hackingwithswift.com/samples/petitions-2.json"
}

Project 10: Names to Faces

關鍵技術:

UICollectionViewController,UICollectionView,UICollectionViewCell,UICollectionViewDataSource,UICollectionViewDelegate,custom cell,cell size,section inset,collectionView(_:didSelectItemAt:),collectionView(_:cellForItemAt:),UIImagePickerControllerDelegate,init,documentDirectory,appendingPathComponent,cornerRadius,UIImagePickerController,allowsEditing,imagePickerController(_:didFinishPickingMediaWithInfo:),originalImage,UUID,write(to:),dismiss,fatalError,NSObject

Project 11: Pachinko(Game)

關鍵技術:

game,SpriteKit,Set,first,SKView,scene,SKScene,anchor point,scaleMode,presentScene,didMove(to:),zPosition,blendMode,replace,SKSpriteNode,rectangleOf,circleOfRadius,edgeLoopFrom,CGPoint,addChild,position,touchesBegan(_:with:),UITouch,location(in:),nodes(at:),CGSize,name,SKAction,rotate,pi,radians,repeatForever,run,isDynamic,SKPhysicsBody,SKPhysicsContactDelegate,physicsWorld,contactDelegate,contactTestBitMask,collisionBitMask,restitution,SKNode,removeFromParent,didBegin(_:),SKPhysicsContact,bodyA,bodyB,node,SKLabelNode,horizontalAlignmentMode,SKEmitterNode,sks,SpriteKit Particle File

Project 12: UserDefaults

關鍵技術:

save,NSKeyedArchiver,archivedData(withRootObject:requiringSecureCoding:),UserDefaults,standard,set(_:forKey:),object(forKey:),data(forKey:),NSKeyedUnarchiver,unarchiveTopLevelObjectWithData,NSCoding,init(coder:),encode(with:),decodeObject(forKey:),encode(_:forKey:),JSONDecoder,JSONEncoder,encode,Codable

Project 13: Instafilter

關鍵技術:

UISlider,editedImage,CoreImage,CIFilter,CIContext,outputImage,UIImageWriteToSavedPhotosAlbum,CIImage,createCGImage(_:from:),CGImage,inputKeys,func image(_ image: UIImage, didFinishSavingWithError error: NSError?, contextInfo: UnsafeRawPointer),localizedDescription

Project 14: Whack-a-Penguin(Game)

關鍵技術:

SKCropNode,maskNode,moveBy(x:y:duration:),SKTexture,asyncAfter(deadline:qos:flags:execute:),now,wait(forDuration:),sequence,run(block:),parent,playSoundFileNamed(_:waitForCompletion:),scale

ps: GameViewController 裡的 scaleMode 請改成 fill。

scene.scaleMode = .fill

Project 15: Animation

關鍵技術:

Core Animation,center,animate(withDuration:animations:completion:),spring animation,animate(withDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion:) ,transform,CGAffineTransform,identity,translation,scale,rotationAngle,alpha,clear

Project 16: Capital Cities

關鍵技術:

map,MapKit,MKMapView,CLLocationCoordinate2D,latitude,longitude,annotation,MKAnnotation,addAnnotation,MKMapViewDelegate,mapView(_:viewFor:),MKAnnotationView,dequeueReusableAnnotationView(withIdentifier:),MKMarkerAnnotationView,canShowCallout,rightCalloutAccessoryView,detailDisclosure,mapView(_:annotationView:calloutAccessoryControlTapped:)

ps:

請將程式裡的 MKPinAnnotationView 改成 MKMarkerAnnotationView

Project 17: Space Race(Game)

關鍵技術:

SKEmitterNode,advanceSimulationTime,gravity,CGVector,Timer,scheduledTimer(timeInterval:target:selector:userInfo:repeats:),invalidate,velocity,angularVelocity,linearDamping,angularDamping,update(_:),touchesMoved(_:with:),CADisplayLink

ps: GameViewController 裡的 scaleMode 請改成 fill。

scene.scaleMode = .fill

Project 18: Debugging

關鍵技術:

debug,print,assert,breakpoint,debug view hierarchy

Project 19: JavaScript Injection

關鍵技術:

Application Extension,Safari extension,JavaScript,JavaScript Injection,NSExtensionItem,extensionContext,inputItems,attachments,NSItemProvider,loadItem(forTypeIdentifier:options:completionHandler:),NSDictionary,NSExtension,NSExtensionAttributes,NSExtensionJavaScriptPreprocessingResultsKey,completeRequest(returningItems:),UITextView,NotificationCenter,default,addObserver(_:selector:name:object:),UIResponder,keyboardWillHideNotification,keyboardWillChangeFrameNotification,keyboardFrameEndUserInfoKey,convert(_:from:),cgRectValue,contentInset,UIEdgeInsets,safeAreaInsets,scrollIndicatorInsets,selectedRange,scrollRangeToVisible,NSExtensionJavaScriptFinalizeArgumentKey,completeRequest(returningItems:),Notification.Name,post(name:object:userInfo:)

ps: adjustForKeyboard 裡的 script.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardViewEndFrame.height, right: 0) 請改成以下寫法。

script.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardViewEndFrame.height - view.safeAreaInsets.bottom, right: 0)

App 操作:

打開 Safari App,從選單點選 Extension,輸入 JavaScript 程式 alert(document.title),點選 Done 關閉頁面時會跳出 alert。

Project 20: Fireworks Night(Game)

關鍵技術:

UIBezierPath,move(to:),addLine(to:),follow(_:asOffset:orientToPath:speed:),children,colorBlendFactor,reversed,for case let,motionBegan(_:with:),shake

ps: checkTouches 的寫法有更新,請改成以下寫法。

func checkTouches(_ touches: Set<UITouch>) {
guard let touch = touches.first else { return }

let location = touch.location(in: self)
let nodesAtPoint = nodes(at: location)

for case let node as SKSpriteNode in nodesAtPoint {
guard node.name == "firework" else { return }

for parent in fireworks {
guard let firework = parent.children.first as? SKSpriteNode else {
continue
}
if firework.name == "selected" && firework.color != node.color {
firework.name = "firework"
firework.colorBlendFactor = 1
}
}

node.name = "selected"
node.colorBlendFactor = 0
}

}

Project 21: Local Notifications

關鍵技術:

local notification,UserNotifications,UNUserNotificationCenter,current,requestAuthorization(options:completionHandler:),alert,badge,sound,UNMutableNotificationContent,title,body,userInfo,UNNotificationSound,categoryIdentifier,DateComponents,UNCalendarNotificationTrigger,UNTimeIntervalNotificationTrigger,UNNotificationRequest,removeAllPendingNotificationRequests,UNNotificationAction,UNNotificationAction(identifier:title:options:),UNNotificationCategory,setNotificationCategories,UNUserNotificationCenterDelegate,userNotificationCenter(_:didReceive:withCompletionHandler:),UNNotificationResponse,actionIdentifier

Project 22: Detect-a-Beacon

關鍵技術:

CoreLocation,CLLocationManager,CLLocationManagerDelegate,requestAlwaysAuthorization,requestWhenInUseAuthorization,locationManager(_:didChangeAuthorization:),locationManagerDidChangeAuthorization(_:),CLAuthorizationStatus,authorizedAlways,isMonitoringAvailable(for:),CLBeaconRegion,isRangingAvailable,iBeacon,CLBeaconRegion(uuid:major:minor:identifier:),startMonitoring(for:),startRangingBeacons(in:),CLBeacon,proximity,CLProximity,unknown,far,near,immediate,locationManager(_:didRangeBeacons:in:),requestLocation,locationManager(_:didUpdateLocations:),locationManager(_:didFailWithError:),startMonitoringVisits,locationManager(_:didVisit:)

ps:

  • locationManager(_:didChangeAuthorization:) 可改成以下新版寫法
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
if manager.authorizationStatus == .authorizedAlways {
if CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self) {
if CLLocationManager.isRangingAvailable() {
startScanning()
}
}
}
}
  • let beaconRegion = CLBeaconRegion(proximityUUID: uuid, major: 123, minor: 456, identifier: "MyBeacon") 可改成以下新版寫法
let beaconRegion = CLBeaconRegion(uuid: uuid, major: 123, minor: 456, identifier: "MyBeacon")
  • locationManager.startRangingBeacons(in: beaconRegion) 可改成以下新版寫法
locationManager.startRangingBeacons(satisfying: CLBeaconIdentityConstraint(uuid: uuid, major: 123, minor: 456))

Project 23: Swifty Ninja(Game)

關鍵技術:

SKShapeNode,strokeColor,touchesEnded(_:with:),touchesCancelled(_:with:),fadeOut(withDuration:),CGPath,run(_:completion:),AVFoundation,AVAudioPlayer,play,stop,CaseIterable,allCases,scale(to:duration:),group,removeAllActions,index(of:),removeFirst

ps:

  • GameViewController 裡的 scaleMode 請改成 fill。
scene.scaleMode = .fill
  • redrawActiveSlice 裡的 while activeSlicePoints.count > 12 {
    activeSlicePoints.remove(at: 0) }
    請改成以下程式。
if activeSlicePoints.count > 12 {

activeSlicePoints.removeFirst(activeSlicePoints.count - 12)
}

Project 24: Swift Strings

關鍵技術:

playground,index(_:offsetBy:),hasPrefix,hasSuffix,dropFirst,dropLast,capitalized,Character,contains(where:),NSAttributedString,NSMutableAttributedString,addAttribute(_:value:range:),underlineStyle,attributedText

Project 25: Selfie Share

關鍵技術:

MultipeerConnectivity,viewWithTag,MCPeerID,UIDevice,MCSession,MCSession(peer:securityIdentity:encryptionPreference:),MCAdvertiserAssistant,MCAdvertiserAssistant(serviceType:discoveryInfo:session:),start,MCBrowserViewController,MCBrowserViewController(serviceType:session:),MCSessionDelegate,MCBrowserViewControllerDelegate,session(_:didReceive:withName:fromPeer:),session(_:didStartReceivingResourceWithName:fromPeer:with:),session(_:didFinishReceivingResourceWithName:fromPeer:at:withError:),session(_:peer:didChange:),MCSessionState,connected,session(_:didReceive:fromPeer:),browserViewControllerDidFinish(_:),browserViewControllerWasCancelled(_:),connectedPeers,pngData,send(_:toPeers:with:),reliable

Project 26: Marble Maze(Game)

關鍵技術:

bitmask,UInt32,categoryBitMask,rawValue,allowsRotation,CoreMotion,CMMotionManager,startAccelerometerUpdates,accelerometerData,acceleration,#if targetEnvironment(simulator),#if swift(>=5.0),compiler directives

ps: GameViewController 裡的 scaleMode 請改成 fill。

scene.scaleMode = .fill

Project 27: Core Graphics

關鍵技術:

Core Graphics,draw 2D,UIGraphicsImageRenderer,image(actions:),UIGraphicsImageRendererContext,CGContext,setFillColor,setStrokeColor,setLineWidth,addRect,drawPath(using:),addEllipse(in:),insetBy(dx:dy:),fill,translateBy,rotate,strokePath,move(to:),addLine(to:),NSMutableParagraphStyle,draw(with:options:attributes:context:),draw(at:)

Project 28: Secret Swift

關鍵技術:

keychain,KeychainWrapper,resignFirstResponder,UIApplication.willResignActiveNotification,Touch ID,Face ID,LocalAuthentication,LAContext,canEvaluatePolicy(_:error:),deviceOwnerAuthenticationWithBiometrics,evaluatePolicy(_:localizedReason:reply:),Privacy — Face ID Usage Description

ps: adjustForKeyboard 裡的 script.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardViewEndFrame.height, right: 0) 請改成以下寫法。

script.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardViewEndFrame.height - view.safeAreaInsets.bottom, right: 0)

Project 29: Exploding Monkeys(Game)

關鍵技術:

SKPhysicsBody(texture:size:),stride(from:to:by:),setFill,texture atlases,usesPreciseCollisionDetection,setTexture,applyImpulse,SKTransition,crossFade(withDuration:),presentScene(_:transition:),doorway(withDuration:),setBlendMode,UIColor(hue:saturation:brightness:alpha:),clear,mix UIKit and SpriteKit

ps: 將 drawBuilding 裡的 ctx.cgContext.setFillColor(color.cgColor)ctx.cgContext.setFillColor(lightOnColor.cgColor)ctx.cgContext.setFillColor(lightOffColor.cgColor) 改成以下程式

color.setFill()
lightOnColor.setFill()
lightOffColor.setFill()

Project 30: Instruments

關鍵技術:

Instrument,profiling,shadow,image caching,Time Profiler,clip,shadowColor,shadowOpacity,shadowRadius,shadowOffset,setShadow(offset:blur:color:),shadowPath,Allocations,register(_:forCellReuseIdentifier:),UIImage(contentsOfFile:)

Project 31: Multibrowser

關鍵技術:

UIStackView,axis,vertical,horizontal,Distribution: (Fill,Fill Equally,Fill Proportionally,Equal Spacing,Equal Centering),arrangedSubviews,UITextFieldDelegate,UIGestureRecognizer,UITapGestureRecognizer,addGestureRecognizer,UIGestureRecognizerDelegate,gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:),textFieldShouldReturn(_:),iPad multitasking,traitCollectionDidChange(_:),UITraitCollection,horizontalSizeClass,verticalSizeClass,compact,regular,absoluteString

ps: 網頁的教學有更新,請移除 deleteWebView 裡的 stackView.removeArrangedSubview(webView)

Project 32: SwiftSearcher

關鍵技術:

automatic UITableViewCell sizing, Dynamic Type,preferredFont(forTextStyle:),SafariServices,SFSafariViewController,entersReaderIfAvailable,SFSafariViewController.Configuration,allowsSelectionDuringEditing,isEditing,editingAccessoryType,checkmark,tableView(_:editingStyleForRowAt:),UITableViewCell.EditingStyle,delete,insert,tableView(_:commit:forRowAt:),reloadRows(at:with:),CoreSpotlight,MobileCoreServices,CSSearchableItemAttributeSet,kUTTypeText,CSSearchableItem,CSSearchableIndex,indexSearchableItems(_:completionHandler:),deleteSearchableItems(withIdentifiers:completionHandler:),application(_:continue:restorationHandler:),NSUserActivity,activityType,CSSearchableItemActionType

Project 33: What’s that Whistle?

關鍵技術:

AVAudioSession,AVAudioRecorder,sharedInstance,setCategory(_:mode:options:),playAndRecord,setActive,requestRecordPermission(_:),numberOfLines,AVFormatIDKey,record,stop,AVAudioRecorderDelegate,audioRecorderDidFinishRecording(_:successfully:),accessoryType,disclosureIndicator,iCloud,CloudKit,hidesBackButton,popToRootViewController(animated:),CKRecord,CKRecord(recordType:),CKRecordValue,CKAsset,CKAsset(fileURL:),fileURL,CKContainer,publicCloudDatabase,save(_:completionHandler:),CloudKit dashboard,deselectRow(at:animated:),NSPredicate,NSPredicate(value:),NSSortDescriptor,NSSortDescriptor(key:ascending:),CKQuery,CKQuery(recordType:predicate:),sortDescriptors,CKQueryOperation,CKQueryOperation(query:),desiredKeys,resultsLimit,recordFetchedBlock,queryCompletionBlock,selectionStyle,CKRecord.Reference,CKRecord.Reference(recordID: action:),perform(_:inZoneWith:completionHandler:),startAnimating,fetch(withRecordID:completionHandler:),push notification,fetchAllSubscriptions(completionHandler:),delete(withSubscriptionID:completionHandler:),CKQuerySubscription,CKQuerySubscription(recordType:predicate:options:),CKSubscription.NotificationInfo,alertBody,registerForRemoteNotifications,userNotificationCenter(_:willPresent:withCompletionHandler:)

project 34 ~ 37 大部分是跟遊戲相關的技術,彼得潘先偷懶跳過,之後有空再研究。

Project 34: Four in a Row(Game)

Project 35: Generating random numbers

Project 36: Crashy Plane(Game)

Project 37: Psychic Tester(Game)

Project 38: GitHub Commits

關鍵技術:

CoreData,Data Model,xcdatamodeld,entity,attribute,NSPersistentContainer,loadPersistentStores(completionHandler:),NSManagedObjectContext,viewContext,NSManagedObject, @NSManaged@nonobjc,NSFetchRequest,fetch,SwiftyJSON,ISO8601DateFormatter,NSMergeByPropertyObjectTrumpMergePolicy,mergePolicy,NSPredicate(format:),Core Data entity relationship,delete,deleteRows(at:with:),fetchLimit,NSFetchedResultsController,NSFetchedResultsController(fetchRequest:managedObjectContext:sectionNameKeyPath:cacheName:),fetchRequest,performFetch,NSFetchedResultsControllerDelegate,sections,NSFetchedResultsSectionInfo,object(at:)

https://api.github.com/repos/apple/swift/commits?per_page=100

Project 39: Unit testing with XCTest

關鍵技術:

unit test,XCTest,XCTestCase,@testable,setUp,tearDown,XCTAssertEqual,filter,measure(_:),keys,NSCountedSet,sorted(by:),UI test,XCUIApplication

--

--

彼得潘的 iOS App Neverland
彼得潘的 Swift iOS / Flutter App 開發教室

彼得潘的iOS App程式設計入門,文組生的iOS App程式設計入門講師,彼得潘的 Swift 程式設計入門,App程式設計入門作者,http://apppeterpan.strikingly.com