diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..1a28423 Binary files /dev/null and b/.DS_Store differ diff --git a/SwiftBlog.xcodeproj/project.pbxproj b/SwiftBlog.xcodeproj/project.pbxproj index c7e977f..456ab23 100644 --- a/SwiftBlog.xcodeproj/project.pbxproj +++ b/SwiftBlog.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ AE17276719B8E32D00565259 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AE17276619B8E32D00565259 /* Images.xcassets */; }; AE17278B19B8F48100565259 /* WebviewPost.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE17278A19B8F48100565259 /* WebviewPost.swift */; }; AE17278D19B8F5C700565259 /* NavigationBarBackground.png in Resources */ = {isa = PBXBuildFile; fileRef = AE17278C19B8F5C700565259 /* NavigationBarBackground.png */; }; + C93BECD41FF52FB3001C1ECA /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C93BECD31FF52FB3001C1ECA /* Launch Screen.storyboard */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -24,6 +25,7 @@ AE17276619B8E32D00565259 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; AE17278A19B8F48100565259 /* WebviewPost.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebviewPost.swift; sourceTree = ""; }; AE17278C19B8F5C700565259 /* NavigationBarBackground.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = NavigationBarBackground.png; sourceTree = ""; }; + C93BECD31FF52FB3001C1ECA /* Launch Screen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -56,6 +58,7 @@ AE17275C19B8E32D00565259 /* SwiftBlog */ = { isa = PBXGroup; children = ( + C93BECD31FF52FB3001C1ECA /* Launch Screen.storyboard */, AE17275F19B8E32D00565259 /* AppDelegate.swift */, AE17276119B8E32D00565259 /* TableViewController.swift */, AE17278A19B8F48100565259 /* WebviewPost.swift */, @@ -101,7 +104,7 @@ AE17275219B8E32D00565259 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0600; + LastUpgradeCheck = 0920; ORGANIZATIONNAME = "Patrick Balestra"; TargetAttributes = { AE17275919B8E32D00565259 = { @@ -134,6 +137,7 @@ files = ( AE17276519B8E32D00565259 /* Main.storyboard in Resources */, AE17276719B8E32D00565259 /* Images.xcassets in Resources */, + C93BECD41FF52FB3001C1ECA /* Launch Screen.storyboard in Resources */, AE17278D19B8F5C700565259 /* NavigationBarBackground.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -173,20 +177,30 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 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_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -199,11 +213,12 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -215,13 +230,21 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 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_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -229,15 +252,18 @@ ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.0; VALIDATE_PRODUCT = YES; }; name = Release; @@ -249,7 +275,9 @@ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; INFOPLIST_FILE = SwiftBlog/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.giovannibalestra.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -260,7 +288,9 @@ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; INFOPLIST_FILE = SwiftBlog/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.giovannibalestra.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.0; }; name = Release; }; diff --git a/SwiftBlog.xcodeproj/project.xcworkspace/xcuserdata/eliotthauteclair.xcuserdatad/UserInterfaceState.xcuserstate b/SwiftBlog.xcodeproj/project.xcworkspace/xcuserdata/eliotthauteclair.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..6923512 Binary files /dev/null and b/SwiftBlog.xcodeproj/project.xcworkspace/xcuserdata/eliotthauteclair.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/SwiftBlog.xcodeproj/xcuserdata/eliotthauteclair.xcuserdatad/xcschemes/xcschememanagement.plist b/SwiftBlog.xcodeproj/xcuserdata/eliotthauteclair.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..0716179 --- /dev/null +++ b/SwiftBlog.xcodeproj/xcuserdata/eliotthauteclair.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + SwiftBlog.xcscheme + + orderHint + 0 + + + + diff --git a/SwiftBlog/AppDelegate.swift b/SwiftBlog/AppDelegate.swift index dc98328..5c7962f 100644 --- a/SwiftBlog/AppDelegate.swift +++ b/SwiftBlog/AppDelegate.swift @@ -13,33 +13,31 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - - func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool { - - UIApplication.sharedApplication().statusBarStyle = UIStatusBarStyle.LightContent + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool { + UIApplication.shared.statusBarStyle = .lightContent return true } - func applicationWillResignActive(application: UIApplication!) { + func applicationWillResignActive(_ application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - func applicationDidEnterBackground(application: UIApplication!) { + func applicationDidEnterBackground(_ application: UIApplication) { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - func applicationWillEnterForeground(application: UIApplication!) { + func applicationWillEnterForeground(_ application: UIApplication) { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - func applicationDidBecomeActive(application: UIApplication!) { + func applicationDidBecomeActive(_ application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - func applicationWillTerminate(application: UIApplication!) { + func applicationWillTerminate(_ application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } diff --git a/SwiftBlog/Base.lproj/Main.storyboard b/SwiftBlog/Base.lproj/Main.storyboard index 22851ee..6977e8e 100644 --- a/SwiftBlog/Base.lproj/Main.storyboard +++ b/SwiftBlog/Base.lproj/Main.storyboard @@ -1,7 +1,12 @@ - - + + + + + - + + + @@ -9,22 +14,26 @@ - + - + + + - + - + @@ -103,12 +118,4 @@ - - - - - - - - diff --git a/SwiftBlog/Images.xcassets/AppIcon.appiconset/Contents.json b/SwiftBlog/Images.xcassets/AppIcon.appiconset/Contents.json index a396706..19882d5 100644 --- a/SwiftBlog/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/SwiftBlog/Images.xcassets/AppIcon.appiconset/Contents.json @@ -1,19 +1,49 @@ { "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" } ], "info" : { diff --git a/SwiftBlog/Info.plist b/SwiftBlog/Info.plist index ac9b78c..0e7c01a 100644 --- a/SwiftBlog/Info.plist +++ b/SwiftBlog/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - com.giovannibalestra.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName @@ -22,6 +22,8 @@ 1 LSRequiresIPhoneOS + UILaunchStoryboardName + Launch Screen UIMainStoryboardFile Main UIRequiredDeviceCapabilities diff --git a/SwiftBlog/Launch Screen.storyboard b/SwiftBlog/Launch Screen.storyboard new file mode 100644 index 0000000..1b82485 --- /dev/null +++ b/SwiftBlog/Launch Screen.storyboard @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SwiftBlog/TableViewController.swift b/SwiftBlog/TableViewController.swift index 2df7cf6..7383ac0 100644 --- a/SwiftBlog/TableViewController.swift +++ b/SwiftBlog/TableViewController.swift @@ -15,9 +15,9 @@ class BlogPost { var date = String() } -class TableViewController: UITableViewController, NSXMLParserDelegate { +class TableViewController: UITableViewController, XMLParserDelegate { - var parser = NSXMLParser() + var parser = XMLParser() var blogPosts: [BlogPost] = [] var eName = String() @@ -28,28 +28,27 @@ class TableViewController: UITableViewController, NSXMLParserDelegate { override func viewDidLoad() { super.viewDidLoad() - - tableView.frame = CGRectMake(0, 0, 320, 568) - - navigationController.navigationBar.tintColor = UIColor.whiteColor() - navigationController.navigationBar.setBackgroundImage(UIImage(named: "NavigationBarBackground"), forBarMetrics: .Default) - navigationController.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName:UIColor.whiteColor(), NSFontAttributeName:UIFont(name: "HelveticaNeue-Light", size: 18)] - navigationController.navigationBar.shadowImage = UIImage() + + navigationController?.navigationBar.tintColor = UIColor.white + navigationController?.navigationBar.setBackgroundImage(UIImage(named: "NavigationBarBackground"), for: .default) + navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor:UIColor.white, NSAttributedStringKey.font:UIFont(name: "HelveticaNeue-Light", size: 18)!] + navigationController?.navigationBar.shadowImage = UIImage() tableView.estimatedRowHeight = 100 tableView.rowHeight = UITableViewAutomaticDimension - var url: NSURL = NSURL.URLWithString("https://developer.apple.com/swift/blog/news.rss") - parser = NSXMLParser(contentsOfURL: url) + let url = URL(string: "https://developer.apple.com/swift/blog/news.rss") +// var url: URL = URL.URLWithString("https://developer.apple.com/swift/blog/news.rss")! + parser = XMLParser(contentsOf: url!)! parser.delegate = self parser.parse() - let contents = NSString(contentsOfURL: url, encoding: 0, error: nil) + //let contents = String.init(contentsOf: url!, encoding: String.Encoding(rawValue: 0)) +// let contents = String(contentsOf: url, encoding: 0, error: nil) } - func parser(parser: NSXMLParser!, didStartElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!, attributes attributeDict: [NSObject : AnyObject]!) { - + func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { eName = elementName if elementName == "item" { postTitle = String() @@ -59,7 +58,7 @@ class TableViewController: UITableViewController, NSXMLParserDelegate { } } - func parser(parser: NSXMLParser!, didEndElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!) { + func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { if elementName == "item" { let blogPost: BlogPost = BlogPost() blogPost.title = postTitle @@ -70,8 +69,10 @@ class TableViewController: UITableViewController, NSXMLParserDelegate { } } - func parser(parser: NSXMLParser!, foundCharacters string: String!) { - let data = string.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) + func parser(_ parser: XMLParser, foundCharacters string: String) { + let data = string.trimmingCharacters(in: NSCharacterSet.whitespacesAndNewlines) + //let data = string.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) + if (!data.isEmpty) { if eName == "title" { postTitle += data @@ -80,44 +81,43 @@ class TableViewController: UITableViewController, NSXMLParserDelegate { } else if eName == "description" { descriptionText += data } else if eName == "pubDate" { - let dateFormatter = NSDateFormatter() + let dateFormatter = DateFormatter() dateFormatter.dateFormat = "EEE, dd LLL yyyy HH:mm:ss zzz" - dateFormatter.timeZone = NSTimeZone(abbreviation: "PDT") - let formattedDate = dateFormatter.dateFromString(data) + dateFormatter.timeZone = TimeZone(abbreviation: "PDT") + let formattedDate = dateFormatter.date(from: data) if formattedDate != nil { - dateFormatter.dateStyle = .MediumStyle; - dateFormatter.timeStyle = .NoStyle; - postDate = dateFormatter.stringFromDate(formattedDate!) + dateFormatter.dateStyle = .medium + dateFormatter.timeStyle = .none + postDate = dateFormatter.string(from: formattedDate!) } } } } - func parserDidEndDocument(parser: NSXMLParser!) { + func parserDidEndDocument(_ parser: XMLParser) { self.tableView.reloadData() } // MARK: - Table view data source - - override func numberOfSectionsInTableView(tableView: UITableView!) -> Int { + override func numberOfSections(in tableView: UITableView) -> Int { return 1 } - override func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int { + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return blogPosts.count } - override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { - let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as UITableViewCell let currentBlogPost: BlogPost = blogPosts[indexPath.row] - cell.textLabel.text = currentBlogPost.title - cell.detailTextLabel.text = currentBlogPost.description - cell.textLabel.numberOfLines = 0 - cell.detailTextLabel.numberOfLines = 1 + cell.textLabel?.text = currentBlogPost.title + cell.detailTextLabel?.text = currentBlogPost.description + cell.textLabel?.numberOfLines = 0 + cell.detailTextLabel?.numberOfLines = 1 - let dateLabel = UILabel(frame: CGRectMake(0, 0, 80, 25)) - dateLabel.textColor = UIColor.orangeColor() - dateLabel.textAlignment = .Right; + let dateLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 80, height: 25)) + dateLabel.textColor = UIColor.orange + dateLabel.textAlignment = .right dateLabel.font = UIFont(name: "HelveticaNeue-Light", size: 12) dateLabel.text = currentBlogPost.date cell.accessoryView = dateLabel @@ -125,10 +125,10 @@ class TableViewController: UITableViewController, NSXMLParserDelegate { return cell } - override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) { + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if (segue.identifier == "post") { - let webView: WebviewPost = segue!.destinationViewController as WebviewPost - webView.blogPostURL = NSURL(string:blogPosts[tableView.indexPathForSelectedRow().row].link) + let webView: WebviewPost = segue.destination as! WebviewPost + webView.blogPostURL = URL(string:blogPosts[(tableView.indexPathForSelectedRow?.row)!].link) } } diff --git a/SwiftBlog/WebviewPost.swift b/SwiftBlog/WebviewPost.swift index cf71738..c6095cf 100644 --- a/SwiftBlog/WebviewPost.swift +++ b/SwiftBlog/WebviewPost.swift @@ -12,20 +12,20 @@ class WebviewPost: UIViewController, UIWebViewDelegate { @IBOutlet weak var webView: UIWebView! - var blogPostURL: NSURL = NSURL() + var blogPostURL: URL? = nil override func viewDidLoad() { - let request = NSURLRequest(URL: blogPostURL) + let request = URLRequest(url: blogPostURL!) webView.loadRequest(request) webView.sizeToFit() - UIApplication.sharedApplication().networkActivityIndicatorVisible = true; + UIApplication.shared.isNetworkActivityIndicatorVisible = true } @IBAction func openInSafari(sender: AnyObject) { - UIApplication.sharedApplication().openURL(blogPostURL) + UIApplication.shared.open(blogPostURL!, options: [:], completionHandler: nil) } - func webViewDidFinishLoad(webView: UIWebView!) { - UIApplication.sharedApplication().networkActivityIndicatorVisible = false; + func webViewDidFinishLoad(_ webView: UIWebView) { + UIApplication.shared.isNetworkActivityIndicatorVisible = false } }